{"version":3,"file":"VectorControl-CiXVbIqz.cjs","names":[],"sources":["../src/lib/ui/dom.ts","../src/lib/ui/layerPicker.ts","../src/lib/formats/detect.ts","../src/lib/utils/geometry.ts","../src/lib/formats/geojsonSniff.ts","../node_modules/fflate/esm/browser.js","../src/lib/formats/kmzMetadata.ts","../src/lib/render/renderMode.ts","../src/lib/render/styleBuilder.ts","../src/lib/render/mapSources.ts","../src/lib/utils/maplibre.ts","../src/lib/tiles/protocol.ts","../src/lib/utils/fit.ts","../src/lib/utils/helpers.ts","../src/lib/utils/remote.ts","../src/lib/core/LayerManager.ts","../src/lib/engine/sql.ts","../src/lib/engine/duckdbLoader.ts","../src/lib/engine/gpkgOgrContents.ts","../src/lib/engine/geopackage.ts","../src/lib/engine/geojsonBytes.ts","../src/lib/tiles/mvtFallback.ts","../src/lib/formats/shapefile.ts","../src/lib/formats/kmz.ts","../src/lib/formats/geoparquetCrs.ts","../src/lib/engine/surfaceWkb.ts","../src/lib/engine/DuckDBEngine.ts","../src/lib/ui/styleEditor.ts","../src/lib/ui/layerListItem.ts","../src/lib/ui/panel.ts","../src/lib/core/VectorControl.ts"],"sourcesContent":["/**\n * Tiny DOM helpers to keep the vanilla UI modules terse.\n */\n\n/**\n * Creates an element with a class name and optional attributes.\n *\n * @param tag - The element tag name\n * @param className - Optional class name\n * @param attrs - Optional attributes to set\n * @returns The created element\n */\nexport function el<K extends keyof HTMLElementTagNameMap>(\n  tag: K,\n  className?: string,\n  attrs?: Record<string, string>,\n): HTMLElementTagNameMap[K] {\n  const element = document.createElement(tag);\n  if (className) element.className = className;\n  if (attrs) {\n    for (const [key, value] of Object.entries(attrs)) {\n      element.setAttribute(key, value);\n    }\n  }\n  return element;\n}\n\n/**\n * Creates an inline SVG icon element from path markup.\n *\n * SECURITY: `paths` is inserted into innerHTML without sanitization.\n * Only pass trusted, static SVG markup such as the {@link ICONS}\n * constants - never user-generated content.\n *\n * @param paths - Trusted SVG inner markup (path/rect/circle elements)\n * @param size - Icon size in pixels\n * @returns A span wrapping the SVG\n */\nexport function svgIcon(paths: string, size = 14): HTMLSpanElement {\n  const span = el('span', 'vector-control-svg-icon');\n  span.innerHTML = `<svg viewBox=\"0 0 24 24\" width=\"${size}\" height=\"${size}\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">${paths}</svg>`;\n  return span;\n}\n\n/**\n * Common SVG icon paths.\n */\nexport const ICONS = {\n  eye: '<path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>',\n  eyeOff:\n    '<path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\"/><path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\"/><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"/>',\n  zoom: '<circle cx=\"11\" cy=\"11\" r=\"8\"/><line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\"/><line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\"/><line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\"/>',\n  trash:\n    '<polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/>',\n  sliders:\n    '<line x1=\"4\" y1=\"21\" x2=\"4\" y2=\"14\"/><line x1=\"4\" y1=\"10\" x2=\"4\" y2=\"3\"/><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"12\"/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"3\"/><line x1=\"20\" y1=\"21\" x2=\"20\" y2=\"16\"/><line x1=\"20\" y1=\"12\" x2=\"20\" y2=\"3\"/><line x1=\"1\" y1=\"14\" x2=\"7\" y2=\"14\"/><line x1=\"9\" y1=\"8\" x2=\"15\" y2=\"8\"/><line x1=\"17\" y1=\"16\" x2=\"23\" y2=\"16\"/>',\n  upload:\n    '<path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><polyline points=\"17 8 12 3 7 8\"/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"/>',\n  chevronDown: '<polyline points=\"6 9 12 15 18 9\"/>',\n} as const;\n","import { el } from './dom';\n\n/**\n * A modal checkbox picker for the layers of a multi-layer container\n * (a GeoPackage with several feature tables, a multi-layer GDAL source,\n * ...), so the user loads only the layers they want instead of every\n * layer in the file.\n */\n\n/** Options for {@link openLayerPicker}. */\nexport interface LayerPickerOptions {\n  /** Element the modal is appended to (normally the map container). */\n  container: HTMLElement;\n  /** Layer names offered, in the container's own order. */\n  layers: string[];\n  /** Display name of the container (file name or URL), shown in the prompt. */\n  sourceName: string;\n}\n\n/** A picker that has been opened (or queued behind an earlier one). */\nexport interface LayerPickerHandle {\n  /** Resolves with the chosen layer names; empty when the user cancelled. */\n  selection: Promise<string[]>;\n  /** Closes the picker as if the user cancelled (resolves with `[]`). */\n  close(): void;\n}\n\n// One picker at a time per container: the panel starts a load per dropped\n// file without awaiting, so two multi-layer files would otherwise stack two\n// modals on top of each other. Each open waits for the previous one to\n// settle, and the chain is keyed by container so separate maps stay\n// independent.\nconst pickerQueues = new WeakMap<HTMLElement, Promise<unknown>>();\n\n/**\n * Opens a modal layer picker over `container` and resolves with the layers\n * the user chose. Every layer starts selected, so confirming without changing\n * anything loads the whole container (the behavior before the picker existed).\n *\n * @param options - The container, the layer names, and the source name.\n * @returns A handle carrying the selection promise and a programmatic close.\n */\nexport function openLayerPicker(options: LayerPickerOptions): LayerPickerHandle {\n  // Closing before the queued turn arrives must still cancel, so the state\n  // lives here rather than inside the (not yet created) modal.\n  let closed = false;\n  let cancelOpenPicker: (() => void) | null = null;\n\n  const show = (): Promise<string[]> =>\n    closed\n      ? Promise.resolve([])\n      : renderLayerPicker(options, (cancel) => {\n          cancelOpenPicker = cancel;\n        });\n\n  const previous = pickerQueues.get(options.container) ?? Promise.resolve();\n  // `.then(show, show)`: a rejected predecessor must not strand this picker.\n  const selection = previous.then(show, show);\n  pickerQueues.set(options.container, selection);\n\n  return {\n    selection,\n    close: () => {\n      closed = true;\n      cancelOpenPicker?.();\n    },\n  };\n}\n\n/**\n * Builds the modal, wires it up, and resolves once the user confirms or\n * cancels. `registerCancel` receives the cancel callback so the caller's\n * handle can close a picker that is already on screen.\n */\nfunction renderLayerPicker(\n  options: LayerPickerOptions,\n  registerCancel: (cancel: () => void) => void,\n): Promise<string[]> {\n  const { container, layers, sourceName } = options;\n\n  return new Promise<string[]>((resolve) => {\n    const titleId = `vector-layer-picker-title-${Math.random().toString(36).slice(2, 10)}`;\n\n    const overlay = el('div', 'vector-control-layer-picker');\n    const dialog = el('div', 'vector-control-layer-picker-dialog', {\n      role: 'dialog',\n      'aria-modal': 'true',\n      'aria-labelledby': titleId,\n    });\n\n    const title = el('div', 'vector-control-layer-picker-title', { id: titleId });\n    title.textContent = 'Choose layers to load';\n    const subtitle = el('div', 'vector-control-layer-picker-subtitle');\n    subtitle.textContent = `${sourceName} contains ${layers.length} layers.`;\n\n    // \"Select all\" sits outside the scrolling list so it stays reachable for a\n    // container with many layers.\n    const selectAllRow = el('label', 'vector-control-layer-picker-all');\n    const selectAll = el('input', 'vector-control-checkbox') as HTMLInputElement;\n    selectAll.type = 'checkbox';\n    selectAll.checked = true;\n    const selectAllText = el('span');\n    selectAllText.textContent = 'Select all';\n    selectAllRow.appendChild(selectAll);\n    selectAllRow.appendChild(selectAllText);\n\n    const list = el('div', 'vector-control-layer-picker-list');\n    const boxes: HTMLInputElement[] = [];\n    for (const layer of layers) {\n      const row = el('label', 'vector-control-layer-picker-item');\n      const box = el('input', 'vector-control-checkbox') as HTMLInputElement;\n      box.type = 'checkbox';\n      box.checked = true;\n      box.value = layer;\n      const text = el('span', 'vector-control-layer-picker-name');\n      // textContent, never innerHTML: a layer name comes from the file.\n      text.textContent = layer;\n      text.title = layer;\n      row.appendChild(box);\n      row.appendChild(text);\n      list.appendChild(row);\n      boxes.push(box);\n    }\n\n    const footer = el('div', 'vector-control-layer-picker-footer');\n    const cancelButton = el('button', 'vector-control-button vector-control-button-secondary', {\n      type: 'button',\n    });\n    cancelButton.textContent = 'Cancel';\n    const loadButton = el('button', 'vector-control-button', { type: 'button' });\n    footer.appendChild(cancelButton);\n    footer.appendChild(loadButton);\n\n    const chosen = (): string[] => boxes.filter((box) => box.checked).map((box) => box.value);\n\n    const syncState = (): void => {\n      const count = chosen().length;\n      selectAll.checked = count === layers.length;\n      selectAll.indeterminate = count > 0 && count < layers.length;\n      loadButton.disabled = count === 0;\n      loadButton.textContent = count === 1 ? 'Load 1 layer' : `Load ${count} layers`;\n    };\n\n    for (const box of boxes) box.addEventListener('change', syncState);\n    selectAll.addEventListener('change', () => {\n      for (const box of boxes) box.checked = selectAll.checked;\n      syncState();\n    });\n    syncState();\n\n    let settled = false;\n    const finish = (result: string[]): void => {\n      if (settled) return;\n      settled = true;\n      overlay.remove();\n      resolve(result);\n    };\n\n    cancelButton.addEventListener('click', () => finish([]));\n    loadButton.addEventListener('click', () => finish(chosen()));\n    // Clicking the backdrop (not the dialog) cancels, like a native dialog.\n    overlay.addEventListener('mousedown', (event) => {\n      if (event.target === overlay) finish([]);\n    });\n    // The overlay sits inside the map container, so let neither the map nor\n    // the control's click-outside handler see clicks meant for the dialog.\n    for (const type of ['mousedown', 'click', 'dblclick', 'wheel'] as const) {\n      overlay.addEventListener(type, (event) => event.stopPropagation());\n    }\n    overlay.addEventListener('keydown', (event) => {\n      if (event.key === 'Escape') {\n        event.stopPropagation();\n        finish([]);\n      }\n    });\n\n    dialog.appendChild(title);\n    dialog.appendChild(subtitle);\n    dialog.appendChild(selectAllRow);\n    dialog.appendChild(list);\n    dialog.appendChild(footer);\n    overlay.appendChild(dialog);\n    container.appendChild(overlay);\n\n    // Focus inside the dialog so Escape and Tab land on it rather than on the\n    // page behind it.\n    selectAll.focus();\n\n    registerCancel(() => finish([]));\n  });\n}\n","import type { VectorDataSource, VectorFormat } from '../core/types';\n\n/**\n * Result of format detection for a data source.\n */\nexport interface DetectedSource {\n  /** Detected vector format */\n  format: VectorFormat;\n  /** Suggested display name (file name without extension, or 'GeoJSON') */\n  name: string;\n}\n\n/**\n * Maps file extensions to vector formats.\n */\nconst EXTENSION_FORMATS: Record<string, VectorFormat> = {\n  geojson: 'geojson',\n  json: 'geojson',\n  gpkg: 'geopackage',\n  shp: 'shapefile',\n  zip: 'shapefile',\n  parquet: 'geoparquet',\n  geoparquet: 'geoparquet',\n  pq: 'geoparquet',\n  fgb: 'flatgeobuf',\n  csv: 'csv',\n  tsv: 'csv',\n  // Not a GDAL-readable path on its own: the engine unzips a KMZ and reads\n  // the KML inside it (see formats/kmz.ts).\n  kmz: 'kmz',\n};\n\n/**\n * Extracts the file name from a URL or path, stripping query strings.\n *\n * @param url - URL or file path\n * @returns The trailing file name segment\n */\nexport function fileNameFromUrl(url: string): string {\n  const withoutQuery = url.split(/[?#]/)[0];\n  const segments = withoutQuery.split('/');\n  return segments[segments.length - 1] || withoutQuery;\n}\n\n/**\n * Detects the vector format from a file name based on its extension.\n *\n * Extensions without a dedicated reader (kml, gml, tab, dxf, ...) are\n * returned as-is and handled by the GDAL-backed ST_Read, so every\n * format the spatial extension supports can load.\n *\n * @param fileName - File name or URL path\n * @returns The detected format, or 'unknown' when there is no extension\n */\nexport function formatFromFileName(fileName: string): VectorFormat {\n  const match = /\\.([a-z0-9]+)$/i.exec(fileName.trim());\n  if (!match) return 'unknown';\n  const extension = match[1].toLowerCase();\n  return EXTENSION_FORMATS[extension] ?? extension;\n}\n\n/**\n * Strips the extension from a file name for display purposes.\n *\n * @param fileName - File name\n * @returns File name without its extension\n */\nexport function baseName(fileName: string): string {\n  return fileName.replace(/\\.[a-z0-9]+$/i, '') || fileName;\n}\n\n/**\n * Maps data: URL MIME types to vector formats.\n */\nconst MIME_FORMATS: Array<[RegExp, VectorFormat]> = [\n  [/json/, 'geojson'],\n  [/csv|tab-separated/, 'csv'],\n  [/parquet/, 'geoparquet'],\n];\n\n/**\n * Detects the format of a data: URL from its MIME type.\n *\n * Bundlers (e.g. Vite) inline small assets as base64 data URLs, so a\n * sample.geojson import can reach addData as `data:application/geo+json;...`.\n *\n * @param url - The data: URL\n * @returns The detected format, or 'unknown'\n */\nexport function formatFromDataUrl(url: string): VectorFormat {\n  const mime = url.slice('data:'.length).split(/[;,]/)[0].toLowerCase();\n  for (const [pattern, format] of MIME_FORMATS) {\n    if (pattern.test(mime)) return format;\n  }\n  return 'unknown';\n}\n\n/**\n * Detects the format and display name of a data source.\n *\n * GeoJSON objects are recognized directly; files and URLs are detected\n * from their extension (or MIME type for data: URLs). An explicit\n * format always wins.\n *\n * @param source - URL string, File/Blob, or GeoJSON object\n * @param explicitFormat - Optional format override\n * @returns The detected source description\n */\nexport function detectSource(\n  source: VectorDataSource,\n  explicitFormat?: VectorFormat,\n): DetectedSource {\n  if (typeof source === 'string') {\n    if (source.startsWith('data:')) {\n      return { format: explicitFormat ?? formatFromDataUrl(source), name: 'Untitled' };\n    }\n    const name = fileNameFromUrl(source);\n    return {\n      format: explicitFormat ?? formatFromFileName(name),\n      name: baseName(name),\n    };\n  }\n\n  if (typeof File !== 'undefined' && source instanceof File) {\n    return {\n      format: explicitFormat ?? formatFromFileName(source.name),\n      name: baseName(source.name),\n    };\n  }\n\n  if (typeof Blob !== 'undefined' && source instanceof Blob) {\n    return { format: explicitFormat ?? 'unknown', name: 'Untitled' };\n  }\n\n  // Plain object - treat as GeoJSON\n  return { format: explicitFormat ?? 'geojson', name: 'GeoJSON' };\n}\n","import type { Feature, FeatureCollection, GeoJSON, Geometry, Position } from 'geojson';\nimport type { GeometryCategory } from '../core/types';\n\n/**\n * Bounding box as [minX, minY, maxX, maxY] in EPSG:4326.\n */\nexport type Bbox = [number, number, number, number];\n\n/**\n * Classifies a GeoJSON geometry type into a broad category.\n *\n * @param type - GeoJSON geometry type string\n * @returns The geometry category\n */\nexport function classifyGeometryType(type: string): GeometryCategory {\n  switch (type) {\n    case 'Point':\n    case 'MultiPoint':\n      return 'point';\n    case 'LineString':\n    case 'MultiLineString':\n      return 'line';\n    case 'Polygon':\n    case 'MultiPolygon':\n      return 'polygon';\n    case 'GeometryCollection':\n      return 'mixed';\n    default:\n      return 'unknown';\n  }\n}\n\n/**\n * Merges a new category into an accumulated category.\n *\n * @param current - The accumulated category (undefined when empty)\n * @param next - The next category seen\n * @returns The merged category\n */\nexport function mergeGeometryCategory(\n  current: GeometryCategory | undefined,\n  next: GeometryCategory,\n): GeometryCategory {\n  if (!current || current === 'unknown') return next;\n  if (next === 'unknown') return current;\n  return current === next ? current : 'mixed';\n}\n\n/**\n * Normalizes any GeoJSON object into a FeatureCollection.\n *\n * @param data - GeoJSON object (FeatureCollection, Feature, or Geometry)\n * @returns The data as a FeatureCollection\n */\nexport function toFeatureCollection(data: GeoJSON): FeatureCollection {\n  if (data.type === 'FeatureCollection') return data;\n  if (data.type === 'Feature') return { type: 'FeatureCollection', features: [data] };\n  return {\n    type: 'FeatureCollection',\n    features: [{ type: 'Feature', geometry: data as Geometry, properties: {} }],\n  };\n}\n\n/**\n * Reads the source CRS declared by a GeoJSON `crs` member and returns it as an\n * `EPSG:<code>` string to reproject from, or null when the collection is already\n * WGS84 lon/lat (or carries no usable CRS member).\n *\n * RFC 7946 mandates WGS84 for GeoJSON, but the pre-RFC form with a top-level\n * `\"crs\": { \"type\": \"name\", \"properties\": { \"name\": \"urn:ogc:def:crs:EPSG::26911\" } }`\n * is still emitted by GDAL/QGIS exports of projected data. Such a collection\n * carries raw projected coordinates (metres) that MapLibre cannot render, so the\n * caller reprojects to WGS84 before adding the layer. Both the URN form\n * (`urn:ogc:def:crs:EPSG::26911`) and the short form (`EPSG:26911`) are handled.\n *\n * WGS84 aliases (`EPSG:4326`, `EPSG:4979`, and OGC `CRS84`) return null so the\n * already-WGS84 common case skips the reprojection round-trip entirely.\n *\n * @param collection - A FeatureCollection that may carry a legacy `crs` member\n * @returns An `EPSG:<code>` string to reproject from, or null when none is needed\n */\nexport function crsFromGeoJSON(collection: FeatureCollection): string | null {\n  const name = (collection as { crs?: { properties?: { name?: unknown } } }).crs?.properties?.name;\n  if (typeof name !== 'string') return null;\n  const upper = name.toUpperCase();\n  // CRS84 (lon/lat) and the WGS84 EPSG codes are already the coordinates\n  // MapLibre expects, so no reprojection is required.\n  if (upper.includes('CRS84') || /EPSG:+(4326|4979)\\b/.test(upper)) return null;\n  // Match the trailing EPSG code in either the URN (`EPSG::26911`) or short\n  // (`EPSG:26911`) form; the `:+` tolerates the URN's double colon.\n  const match = upper.match(/EPSG:+(\\d+)/);\n  return match ? `EPSG:${match[1]}` : null;\n}\n\nfunction extendBboxWithPositions(bbox: Bbox, coords: unknown): void {\n  if (!Array.isArray(coords)) return;\n  if (typeof coords[0] === 'number') {\n    const [x, y] = coords as Position;\n    if (x < bbox[0]) bbox[0] = x;\n    if (y < bbox[1]) bbox[1] = y;\n    if (x > bbox[2]) bbox[2] = x;\n    if (y > bbox[3]) bbox[3] = y;\n    return;\n  }\n  for (const child of coords) {\n    extendBboxWithPositions(bbox, child);\n  }\n}\n\nfunction extendBboxWithGeometry(bbox: Bbox, geometry: Geometry | null): void {\n  if (!geometry) return;\n  if (geometry.type === 'GeometryCollection') {\n    for (const child of geometry.geometries) {\n      extendBboxWithGeometry(bbox, child);\n    }\n    return;\n  }\n  extendBboxWithPositions(bbox, geometry.coordinates);\n}\n\n/**\n * Summary statistics of a FeatureCollection.\n */\nexport interface GeoJSONSummary {\n  featureCount: number;\n  geometryType: GeometryCategory;\n  bbox?: Bbox;\n}\n\n/**\n * Computes feature count, geometry category, and bounding box of a\n * FeatureCollection in a single pass.\n *\n * @param collection - The FeatureCollection to summarize\n * @returns Summary statistics\n */\nexport function summarizeFeatureCollection(collection: FeatureCollection): GeoJSONSummary {\n  const bbox: Bbox = [Infinity, Infinity, -Infinity, -Infinity];\n  let category: GeometryCategory | undefined;\n\n  for (const feature of collection.features as Feature[]) {\n    if (feature.geometry) {\n      category = mergeGeometryCategory(category, classifyGeometryType(feature.geometry.type));\n      extendBboxWithGeometry(bbox, feature.geometry);\n    }\n  }\n\n  return {\n    featureCount: collection.features.length,\n    geometryType: category ?? 'unknown',\n    bbox: bbox[0] <= bbox[2] && bbox[1] <= bbox[3] ? bbox : undefined,\n  };\n}\n\n/**\n * Collects the union of attribute (property) names across a collection's\n * features, in first-seen order. A host uses these to offer attribute-driven\n * choices (e.g. a label field) for a loaded layer.\n *\n * @param collection - The FeatureCollection to scan\n * @returns The distinct property names found across all features\n */\nexport function collectFieldNames(collection: FeatureCollection): string[] {\n  const names = new Set<string>();\n  for (const feature of collection.features as Feature[]) {\n    if (!feature.properties) continue;\n    for (const key of Object.keys(feature.properties)) names.add(key);\n  }\n  return Array.from(names);\n}\n","import type { FeatureCollection, GeoJSON } from 'geojson';\nimport { toFeatureCollection } from '../utils/geometry';\n\n/**\n * The `type` values a top-level GeoJSON object can carry (RFC 7946).\n */\nconst GEOJSON_TYPES = new Set([\n  'FeatureCollection',\n  'Feature',\n  'Point',\n  'MultiPoint',\n  'LineString',\n  'MultiLineString',\n  'Polygon',\n  'MultiPolygon',\n  'GeometryCollection',\n]);\n\n/**\n * Whether a parsed value is shaped like a GeoJSON object (a plain object\n * with a recognized `type`).\n *\n * @param value - A value parsed from JSON\n * @returns True when `value` looks like GeoJSON\n */\nexport function looksLikeGeoJSON(value: unknown): value is GeoJSON {\n  return (\n    typeof value === 'object' &&\n    value !== null &&\n    GEOJSON_TYPES.has((value as { type?: unknown }).type as string)\n  );\n}\n\n/**\n * Fetches a remote URL and returns its parsed GeoJSON when the response\n * is GeoJSON, or `null` when it is not.\n *\n * Extensionless service endpoints (OGC API Features `?f=geojson`, ArcGIS\n * REST `query?f=geojson`, custom services with query strings and no file\n * extension) return GeoJSON the file-name detector cannot classify, so it\n * falls through to the DuckDB engine. That engine path lazily installs the\n * spatial extension from a remote repository, which hangs in sandboxed or\n * firewalled environments. Sniffing the response here keeps a GeoJSON\n * endpoint on the pure-JS path, so DuckDB is never loaded for it.\n *\n * The response body is only read when the `Content-Type` is JSON-ish, so a\n * binary endpoint without an extension (a `.parquet` behind a query string,\n * say) is not downloaded as text; its download is cancelled and the caller\n * falls back to the engine. The fetched text is returned alongside the\n * collection so the caller can render it without a second request.\n *\n * @param url - The http(s) URL to probe\n * @returns The parsed collection and its byte size, or `null` when the\n *   source is not a JSON response the caller should treat as GeoJSON\n */\nexport async function sniffRemoteGeoJSON(\n  url: string,\n): Promise<{ collection: FeatureCollection; byteSize: number } | null> {\n  if (!/^https?:\\/\\//i.test(url)) return null;\n\n  let response: Response;\n  try {\n    response = await fetch(url);\n  } catch {\n    // Network/CORS failure: let the engine path attempt the load and\n    // surface its own error rather than masking it here.\n    return null;\n  }\n  if (!response.ok) return null;\n\n  const contentType = response.headers.get('content-type') ?? '';\n  if (!/json/i.test(contentType)) {\n    // Not a JSON response (e.g. application/octet-stream for a parquet\n    // endpoint); don't download the body as text.\n    await response.body?.cancel().catch(() => undefined);\n    return null;\n  }\n\n  let text: string;\n  try {\n    text = await response.text();\n  } catch {\n    return null;\n  }\n\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(text);\n  } catch {\n    // JSON content type but unparsable body; fall back to the engine.\n    return null;\n  }\n\n  if (!looksLikeGeoJSON(parsed)) return null;\n  return { collection: toFeatureCollection(parsed), byteSize: text.length };\n}\n","// DEFLATE is a complex format; to read this code, you should probably check the RFC first:\n// https://tools.ietf.org/html/rfc1951\n// You may also wish to take a look at the guide I made about this program:\n// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad\n// Some of the following code is similar to that of UZIP.js:\n// https://github.com/photopea/UZIP.js\n// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size.\n// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint\n// is better for memory in most engines (I *think*).\nvar ch2 = {};\nvar wk = (function (c, id, msg, transfer, cb) {\n    var w = new Worker(ch2[id] || (ch2[id] = URL.createObjectURL(new Blob([\n        c + ';addEventListener(\"error\",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})'\n    ], { type: 'text/javascript' }))));\n    w.onmessage = function (e) {\n        var d = e.data, ed = d.$e$;\n        if (ed) {\n            var err = new Error(ed[0]);\n            err['code'] = ed[1];\n            err.stack = ed[2];\n            cb(err, null);\n        }\n        else\n            cb(null, d);\n    };\n    w.postMessage(msg, transfer);\n    return w;\n});\n\n// aliases for shorter compressed code (most minifers don't do this)\nvar u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array;\n// fixed length extra bits\nvar fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]);\n// fixed distance extra bits\nvar fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]);\n// code length index map\nvar clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);\n// get base, reverse index map from extra bits\nvar freb = function (eb, start) {\n    var b = new u16(31);\n    for (var i = 0; i < 31; ++i) {\n        b[i] = start += 1 << eb[i - 1];\n    }\n    // numbers here are at max 18 bits\n    var r = new i32(b[30]);\n    for (var i = 1; i < 30; ++i) {\n        for (var j = b[i]; j < b[i + 1]; ++j) {\n            r[j] = ((j - b[i]) << 5) | i;\n        }\n    }\n    return { b: b, r: r };\n};\nvar _a = freb(fleb, 2), fl = _a.b, revfl = _a.r;\n// we can ignore the fact that the other numbers are wrong; they never happen anyway\nfl[28] = 258, revfl[258] = 28;\nvar _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r;\n// map of value to reverse (assuming 16 bits)\nvar rev = new u16(32768);\nfor (var i = 0; i < 32768; ++i) {\n    // reverse table algorithm from SO\n    var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1);\n    x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2);\n    x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4);\n    rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1;\n}\n// create huffman tree from u8 \"map\": index -> code length for code index\n// mb (max bits) must be at most 15\n// TODO: optimize/split up?\nvar hMap = (function (cd, mb, r) {\n    var s = cd.length;\n    // index\n    var i = 0;\n    // u16 \"map\": index -> # of codes with bit length = index\n    var l = new u16(mb);\n    // length of cd must be 288 (total # of codes)\n    for (; i < s; ++i) {\n        if (cd[i])\n            ++l[cd[i] - 1];\n    }\n    // u16 \"map\": index -> minimum code for bit length = index\n    var le = new u16(mb);\n    for (i = 1; i < mb; ++i) {\n        le[i] = (le[i - 1] + l[i - 1]) << 1;\n    }\n    var co;\n    if (r) {\n        // u16 \"map\": index -> number of actual bits, symbol for code\n        co = new u16(1 << mb);\n        // bits to remove for reverser\n        var rvb = 15 - mb;\n        for (i = 0; i < s; ++i) {\n            // ignore 0 lengths\n            if (cd[i]) {\n                // num encoding both symbol and bits read\n                var sv = (i << 4) | cd[i];\n                // free bits\n                var r_1 = mb - cd[i];\n                // start value\n                var v = le[cd[i] - 1]++ << r_1;\n                // m is end value\n                for (var m = v | ((1 << r_1) - 1); v <= m; ++v) {\n                    // every 16 bit value starting with the code yields the same result\n                    co[rev[v] >> rvb] = sv;\n                }\n            }\n        }\n    }\n    else {\n        co = new u16(s);\n        for (i = 0; i < s; ++i) {\n            if (cd[i]) {\n                co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]);\n            }\n        }\n    }\n    return co;\n});\n// fixed length tree\nvar flt = new u8(288);\nfor (var i = 0; i < 144; ++i)\n    flt[i] = 8;\nfor (var i = 144; i < 256; ++i)\n    flt[i] = 9;\nfor (var i = 256; i < 280; ++i)\n    flt[i] = 7;\nfor (var i = 280; i < 288; ++i)\n    flt[i] = 8;\n// fixed distance tree\nvar fdt = new u8(32);\nfor (var i = 0; i < 32; ++i)\n    fdt[i] = 5;\n// fixed length map\nvar flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1);\n// fixed distance map\nvar fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1);\n// find max of array\nvar max = function (a) {\n    var m = a[0];\n    for (var i = 1; i < a.length; ++i) {\n        if (a[i] > m)\n            m = a[i];\n    }\n    return m;\n};\n// read d, starting at bit p and mask with m\nvar bits = function (d, p, m) {\n    var o = (p / 8) | 0;\n    return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m;\n};\n// read d, starting at bit p continuing for at least 16 bits\nvar bits16 = function (d, p) {\n    var o = (p / 8) | 0;\n    return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7));\n};\n// get end of byte\nvar shft = function (p) { return ((p + 7) / 8) | 0; };\n// typed array slice - allows garbage collector to free original reference,\n// while being more compatible than .slice\nvar slc = function (v, s, e) {\n    if (s == null || s < 0)\n        s = 0;\n    if (e == null || e > v.length)\n        e = v.length;\n    // can't use .constructor in case user-supplied\n    return new u8(v.subarray(s, e));\n};\n/**\n * Codes for errors generated within this library\n */\nexport var FlateErrorCode = {\n    UnexpectedEOF: 0,\n    InvalidBlockType: 1,\n    InvalidLengthLiteral: 2,\n    InvalidDistance: 3,\n    StreamFinished: 4,\n    NoStreamHandler: 5,\n    InvalidHeader: 6,\n    NoCallback: 7,\n    InvalidUTF8: 8,\n    ExtraFieldTooLong: 9,\n    InvalidDate: 10,\n    FilenameTooLong: 11,\n    StreamFinishing: 12,\n    InvalidZipData: 13,\n    UnknownCompressionMethod: 14\n};\n// error codes\nvar ec = [\n    'unexpected EOF',\n    'invalid block type',\n    'invalid length/literal',\n    'invalid distance',\n    'stream finished',\n    'no stream handler',\n    ,\n    'no callback',\n    'invalid UTF-8 data',\n    'extra field too long',\n    'date not in range 1980-2099',\n    'filename too long',\n    'stream finishing',\n    'invalid zip data'\n    // determined by unknown compression method\n];\n;\nvar err = function (ind, msg, nt) {\n    var e = new Error(msg || ec[ind]);\n    e.code = ind;\n    if (Error.captureStackTrace)\n        Error.captureStackTrace(e, err);\n    if (!nt)\n        throw e;\n    return e;\n};\n// expands raw DEFLATE data\nvar inflt = function (dat, st, buf, dict) {\n    // source length       dict length\n    var sl = dat.length, dl = dict ? dict.length : 0;\n    if (!sl || st.f && !st.l)\n        return buf || new u8(0);\n    var noBuf = !buf;\n    // have to estimate size\n    var resize = noBuf || st.i != 2;\n    // no state\n    var noSt = st.i;\n    // Assumes roughly 33% compression ratio average\n    if (noBuf)\n        buf = new u8(sl * 3);\n    // ensure buffer can fit at least l elements\n    var cbuf = function (l) {\n        var bl = buf.length;\n        // need to increase size to fit\n        if (l > bl) {\n            // Double or set to necessary, whichever is greater\n            var nbuf = new u8(Math.max(bl * 2, l));\n            nbuf.set(buf);\n            buf = nbuf;\n        }\n    };\n    //  last chunk         bitpos           bytes\n    var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;\n    // total bits\n    var tbts = sl * 8;\n    do {\n        if (!lm) {\n            // BFINAL - this is only 1 when last chunk is next\n            final = bits(dat, pos, 1);\n            // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman\n            var type = bits(dat, pos + 1, 3);\n            pos += 3;\n            if (!type) {\n                // go to end of byte boundary\n                var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l;\n                if (t > sl) {\n                    if (noSt)\n                        err(0);\n                    break;\n                }\n                // ensure size\n                if (resize)\n                    cbuf(bt + l);\n                // Copy over uncompressed data\n                buf.set(dat.subarray(s, t), bt);\n                // Get new bitpos, update byte count\n                st.b = bt += l, st.p = pos = t * 8, st.f = final;\n                continue;\n            }\n            else if (type == 1)\n                lm = flrm, dm = fdrm, lbt = 9, dbt = 5;\n            else if (type == 2) {\n                //  literal                            lengths\n                var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;\n                var tl = hLit + bits(dat, pos + 5, 31) + 1;\n                pos += 14;\n                // length+distance tree\n                var ldt = new u8(tl);\n                // code length tree\n                var clt = new u8(19);\n                for (var i = 0; i < hcLen; ++i) {\n                    // use index map to get real code\n                    clt[clim[i]] = bits(dat, pos + i * 3, 7);\n                }\n                pos += hcLen * 3;\n                // code lengths bits\n                var clb = max(clt), clbmsk = (1 << clb) - 1;\n                // code lengths map\n                var clm = hMap(clt, clb, 1);\n                for (var i = 0; i < tl;) {\n                    var r = clm[bits(dat, pos, clbmsk)];\n                    // bits read\n                    pos += r & 15;\n                    // symbol\n                    var s = r >> 4;\n                    // code length to copy\n                    if (s < 16) {\n                        ldt[i++] = s;\n                    }\n                    else {\n                        //  copy   count\n                        var c = 0, n = 0;\n                        if (s == 16)\n                            n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];\n                        else if (s == 17)\n                            n = 3 + bits(dat, pos, 7), pos += 3;\n                        else if (s == 18)\n                            n = 11 + bits(dat, pos, 127), pos += 7;\n                        while (n--)\n                            ldt[i++] = c;\n                    }\n                }\n                //    length tree                 distance tree\n                var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);\n                // max length bits\n                lbt = max(lt);\n                // max dist bits\n                dbt = max(dt);\n                lm = hMap(lt, lbt, 1);\n                dm = hMap(dt, dbt, 1);\n            }\n            else\n                err(1);\n            if (pos > tbts) {\n                if (noSt)\n                    err(0);\n                break;\n            }\n        }\n        // Make sure the buffer can hold this + the largest possible addition\n        // Maximum chunk size (practically, theoretically infinite) is 2^17\n        if (resize)\n            cbuf(bt + 131072);\n        var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;\n        var lpos = pos;\n        for (;; lpos = pos) {\n            // bits read, code\n            var c = lm[bits16(dat, pos) & lms], sym = c >> 4;\n            pos += c & 15;\n            if (pos > tbts) {\n                if (noSt)\n                    err(0);\n                break;\n            }\n            if (!c)\n                err(2);\n            if (sym < 256)\n                buf[bt++] = sym;\n            else if (sym == 256) {\n                lpos = pos, lm = null;\n                break;\n            }\n            else {\n                var add = sym - 254;\n                // no extra bits needed if less\n                if (sym > 264) {\n                    // index\n                    var i = sym - 257, b = fleb[i];\n                    add = bits(dat, pos, (1 << b) - 1) + fl[i];\n                    pos += b;\n                }\n                // dist\n                var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;\n                if (!d)\n                    err(3);\n                pos += d & 15;\n                var dt = fd[dsym];\n                if (dsym > 3) {\n                    var b = fdeb[dsym];\n                    dt += bits16(dat, pos) & (1 << b) - 1, pos += b;\n                }\n                if (pos > tbts) {\n                    if (noSt)\n                        err(0);\n                    break;\n                }\n                if (resize)\n                    cbuf(bt + 131072);\n                var end = bt + add;\n                if (bt < dt) {\n                    var shift = dl - dt, dend = Math.min(dt, end);\n                    if (shift + bt < 0)\n                        err(3);\n                    for (; bt < dend; ++bt)\n                        buf[bt] = dict[shift + bt];\n                }\n                for (; bt < end; ++bt)\n                    buf[bt] = buf[bt - dt];\n            }\n        }\n        st.l = lm, st.p = lpos, st.b = bt, st.f = final;\n        if (lm)\n            final = 1, st.m = lbt, st.d = dm, st.n = dbt;\n    } while (!final);\n    // don't reallocate for streams or user buffers\n    return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);\n};\n// starting at p, write the minimum number of bits that can hold v to d\nvar wbits = function (d, p, v) {\n    v <<= p & 7;\n    var o = (p / 8) | 0;\n    d[o] |= v;\n    d[o + 1] |= v >> 8;\n};\n// starting at p, write the minimum number of bits (>8) that can hold v to d\nvar wbits16 = function (d, p, v) {\n    v <<= p & 7;\n    var o = (p / 8) | 0;\n    d[o] |= v;\n    d[o + 1] |= v >> 8;\n    d[o + 2] |= v >> 16;\n};\n// creates code lengths from a frequency table\nvar hTree = function (d, mb) {\n    // Need extra info to make a tree\n    var t = [];\n    for (var i = 0; i < d.length; ++i) {\n        if (d[i])\n            t.push({ s: i, f: d[i] });\n    }\n    var s = t.length;\n    var t2 = t.slice();\n    if (!s)\n        return { t: et, l: 0 };\n    if (s == 1) {\n        var v = new u8(t[0].s + 1);\n        v[t[0].s] = 1;\n        return { t: v, l: 1 };\n    }\n    t.sort(function (a, b) { return a.f - b.f; });\n    // after i2 reaches last ind, will be stopped\n    // freq must be greater than largest possible number of symbols\n    t.push({ s: -1, f: 25001 });\n    var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;\n    t[0] = { s: -1, f: l.f + r.f, l: l, r: r };\n    // efficient algorithm from UZIP.js\n    // i0 is lookbehind, i2 is lookahead - after processing two low-freq\n    // symbols that combined have high freq, will start processing i2 (high-freq,\n    // non-composite) symbols instead\n    // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/\n    while (i1 != s - 1) {\n        l = t[t[i0].f < t[i2].f ? i0++ : i2++];\n        r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];\n        t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r };\n    }\n    var maxSym = t2[0].s;\n    for (var i = 1; i < s; ++i) {\n        if (t2[i].s > maxSym)\n            maxSym = t2[i].s;\n    }\n    // code lengths\n    var tr = new u16(maxSym + 1);\n    // max bits in tree\n    var mbt = ln(t[i1 - 1], tr, 0);\n    if (mbt > mb) {\n        // more algorithms from UZIP.js\n        // TODO: find out how this code works (debt)\n        //  ind    debt\n        var i = 0, dt = 0;\n        //    left            cost\n        var lft = mbt - mb, cst = 1 << lft;\n        t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; });\n        for (; i < s; ++i) {\n            var i2_1 = t2[i].s;\n            if (tr[i2_1] > mb) {\n                dt += cst - (1 << (mbt - tr[i2_1]));\n                tr[i2_1] = mb;\n            }\n            else\n                break;\n        }\n        dt >>= lft;\n        while (dt > 0) {\n            var i2_2 = t2[i].s;\n            if (tr[i2_2] < mb)\n                dt -= 1 << (mb - tr[i2_2]++ - 1);\n            else\n                ++i;\n        }\n        for (; i >= 0 && dt; --i) {\n            var i2_3 = t2[i].s;\n            if (tr[i2_3] == mb) {\n                --tr[i2_3];\n                ++dt;\n            }\n        }\n        mbt = mb;\n    }\n    return { t: new u8(tr), l: mbt };\n};\n// get the max length and assign length codes\nvar ln = function (n, l, d) {\n    return n.s == -1\n        ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1))\n        : (l[n.s] = d);\n};\n// length codes generation\nvar lc = function (c) {\n    var s = c.length;\n    // Note that the semicolon was intentional\n    while (s && !c[--s])\n        ;\n    var cl = new u16(++s);\n    //  ind      num         streak\n    var cli = 0, cln = c[0], cls = 1;\n    var w = function (v) { cl[cli++] = v; };\n    for (var i = 1; i <= s; ++i) {\n        if (c[i] == cln && i != s)\n            ++cls;\n        else {\n            if (!cln && cls > 2) {\n                for (; cls > 138; cls -= 138)\n                    w(32754);\n                if (cls > 2) {\n                    w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305);\n                    cls = 0;\n                }\n            }\n            else if (cls > 3) {\n                w(cln), --cls;\n                for (; cls > 6; cls -= 6)\n                    w(8304);\n                if (cls > 2)\n                    w(((cls - 3) << 5) | 8208), cls = 0;\n            }\n            while (cls--)\n                w(cln);\n            cls = 1;\n            cln = c[i];\n        }\n    }\n    return { c: cl.subarray(0, cli), n: s };\n};\n// calculate the length of output from tree, code lengths\nvar clen = function (cf, cl) {\n    var l = 0;\n    for (var i = 0; i < cl.length; ++i)\n        l += cf[i] * cl[i];\n    return l;\n};\n// writes a fixed block\n// returns the new bit pos\nvar wfblk = function (out, pos, dat) {\n    // no need to write 00 as type: TypedArray defaults to 0\n    var s = dat.length;\n    var o = shft(pos + 2);\n    out[o] = s & 255;\n    out[o + 1] = s >> 8;\n    out[o + 2] = out[o] ^ 255;\n    out[o + 3] = out[o + 1] ^ 255;\n    for (var i = 0; i < s; ++i)\n        out[o + i + 4] = dat[i];\n    return (o + 4 + s) * 8;\n};\n// writes a block\nvar wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) {\n    wbits(out, p++, final);\n    ++lf[256];\n    var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l;\n    var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l;\n    var _c = lc(dlt), lclt = _c.c, nlc = _c.n;\n    var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;\n    var lcfreq = new u16(19);\n    for (var i = 0; i < lclt.length; ++i)\n        ++lcfreq[lclt[i] & 31];\n    for (var i = 0; i < lcdt.length; ++i)\n        ++lcfreq[lcdt[i] & 31];\n    var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;\n    var nlcc = 19;\n    for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)\n        ;\n    var flen = (bl + 5) << 3;\n    var ftlen = clen(lf, flt) + clen(df, fdt) + eb;\n    var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];\n    if (bs >= 0 && flen <= ftlen && flen <= dtlen)\n        return wfblk(out, p, dat.subarray(bs, bs + bl));\n    var lm, ll, dm, dl;\n    wbits(out, p, 1 + (dtlen < ftlen)), p += 2;\n    if (dtlen < ftlen) {\n        lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;\n        var llm = hMap(lct, mlcb, 0);\n        wbits(out, p, nlc - 257);\n        wbits(out, p + 5, ndc - 1);\n        wbits(out, p + 10, nlcc - 4);\n        p += 14;\n        for (var i = 0; i < nlcc; ++i)\n            wbits(out, p + 3 * i, lct[clim[i]]);\n        p += 3 * nlcc;\n        var lcts = [lclt, lcdt];\n        for (var it = 0; it < 2; ++it) {\n            var clct = lcts[it];\n            for (var i = 0; i < clct.length; ++i) {\n                var len = clct[i] & 31;\n                wbits(out, p, llm[len]), p += lct[len];\n                if (len > 15)\n                    wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12;\n            }\n        }\n    }\n    else {\n        lm = flm, ll = flt, dm = fdm, dl = fdt;\n    }\n    for (var i = 0; i < li; ++i) {\n        var sym = syms[i];\n        if (sym > 255) {\n            var len = (sym >> 18) & 31;\n            wbits16(out, p, lm[len + 257]), p += ll[len + 257];\n            if (len > 7)\n                wbits(out, p, (sym >> 23) & 31), p += fleb[len];\n            var dst = sym & 31;\n            wbits16(out, p, dm[dst]), p += dl[dst];\n            if (dst > 3)\n                wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst];\n        }\n        else {\n            wbits16(out, p, lm[sym]), p += ll[sym];\n        }\n    }\n    wbits16(out, p, lm[256]);\n    return p + ll[256];\n};\n// deflate options (nice << 13) | chain\nvar deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);\n// empty\nvar et = /*#__PURE__*/ new u8(0);\n// compresses data into a raw DEFLATE buffer\nvar dflt = function (dat, lvl, plvl, pre, post, st) {\n    var s = st.z || dat.length;\n    var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post);\n    // writing to this writes to the output buffer\n    var w = o.subarray(pre, o.length - post);\n    var lst = st.l;\n    var pos = (st.r || 0) & 7;\n    if (lvl) {\n        if (pos)\n            w[0] = st.r >> 3;\n        var opt = deo[lvl - 1];\n        var n = opt >> 13, c = opt & 8191;\n        var msk_1 = (1 << plvl) - 1;\n        //    prev 2-byte val map    curr 2-byte val map\n        var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);\n        var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;\n        var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; };\n        // 24576 is an arbitrary number of maximum symbols per block\n        // 424 buffer for last block\n        var syms = new i32(25000);\n        // length/literal freq   distance freq\n        var lf = new u16(288), df = new u16(32);\n        //  l/lcnt  exbits  index          l/lind  waitdx          blkpos\n        var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;\n        for (; i + 2 < s; ++i) {\n            // hash value\n            var hv = hsh(i);\n            // index mod 32768    previous index mod\n            var imod = i & 32767, pimod = head[hv];\n            prev[imod] = pimod;\n            head[hv] = imod;\n            // We always should modify head and prev, but only add symbols if\n            // this data is not yet processed (\"wait\" for wait index)\n            if (wi <= i) {\n                // bytes remaining\n                var rem = s - i;\n                if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) {\n                    pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);\n                    li = lc_1 = eb = 0, bs = i;\n                    for (var j = 0; j < 286; ++j)\n                        lf[j] = 0;\n                    for (var j = 0; j < 30; ++j)\n                        df[j] = 0;\n                }\n                //  len    dist   chain\n                var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;\n                if (rem > 2 && hv == hsh(i - dif)) {\n                    var maxn = Math.min(n, rem) - 1;\n                    var maxd = Math.min(32767, i);\n                    // max possible length\n                    // not capped at dif because decompressors implement \"rolling\" index population\n                    var ml = Math.min(258, rem);\n                    while (dif <= maxd && --ch_1 && imod != pimod) {\n                        if (dat[i + l] == dat[i + l - dif]) {\n                            var nl = 0;\n                            for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl)\n                                ;\n                            if (nl > l) {\n                                l = nl, d = dif;\n                                // break out early when we reach \"nice\" (we are satisfied enough)\n                                if (nl > maxn)\n                                    break;\n                                // now, find the rarest 2-byte sequence within this\n                                // length of literals and search for that instead.\n                                // Much faster than just using the start\n                                var mmd = Math.min(dif, nl - 2);\n                                var md = 0;\n                                for (var j = 0; j < mmd; ++j) {\n                                    var ti = i - dif + j & 32767;\n                                    var pti = prev[ti];\n                                    var cd = ti - pti & 32767;\n                                    if (cd > md)\n                                        md = cd, pimod = ti;\n                                }\n                            }\n                        }\n                        // check the previous match\n                        imod = pimod, pimod = prev[imod];\n                        dif += imod - pimod & 32767;\n                    }\n                }\n                // d will be nonzero only when a match was found\n                if (d) {\n                    // store both dist and len data in one int32\n                    // Make sure this is recognized as a len/dist with 28th bit (2^28)\n                    syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d];\n                    var lin = revfl[l] & 31, din = revfd[d] & 31;\n                    eb += fleb[lin] + fdeb[din];\n                    ++lf[257 + lin];\n                    ++df[din];\n                    wi = i + l;\n                    ++lc_1;\n                }\n                else {\n                    syms[li++] = dat[i];\n                    ++lf[dat[i]];\n                }\n            }\n        }\n        for (i = Math.max(i, wi); i < s; ++i) {\n            syms[li++] = dat[i];\n            ++lf[dat[i]];\n        }\n        pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);\n        if (!lst) {\n            st.r = (pos & 7) | w[(pos / 8) | 0] << 3;\n            // shft(pos) now 1 less if pos & 7 != 0\n            pos -= 7;\n            st.h = head, st.p = prev, st.i = i, st.w = wi;\n        }\n    }\n    else {\n        for (var i = st.w || 0; i < s + lst; i += 65535) {\n            // end\n            var e = i + 65535;\n            if (e >= s) {\n                // write final block\n                w[(pos / 8) | 0] = lst;\n                e = s;\n            }\n            pos = wfblk(w, pos + 1, dat.subarray(i, e));\n        }\n        st.i = s;\n    }\n    return slc(o, 0, pre + shft(pos) + post);\n};\n// CRC32 table\nvar crct = /*#__PURE__*/ (function () {\n    var t = new Int32Array(256);\n    for (var i = 0; i < 256; ++i) {\n        var c = i, k = 9;\n        while (--k)\n            c = ((c & 1) && -306674912) ^ (c >>> 1);\n        t[i] = c;\n    }\n    return t;\n})();\n// CRC32\nvar crc = function () {\n    var c = -1;\n    return {\n        p: function (d) {\n            // closures have awful performance\n            var cr = c;\n            for (var i = 0; i < d.length; ++i)\n                cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8);\n            c = cr;\n        },\n        d: function () { return ~c; }\n    };\n};\n// Adler32\nvar adler = function () {\n    var a = 1, b = 0;\n    return {\n        p: function (d) {\n            // closures have awful performance\n            var n = a, m = b;\n            var l = d.length | 0;\n            for (var i = 0; i != l;) {\n                var e = Math.min(i + 2655, l);\n                for (; i < e; ++i)\n                    m += n += d[i];\n                n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16);\n            }\n            a = n, b = m;\n        },\n        d: function () {\n            a %= 65521, b %= 65521;\n            return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8);\n        }\n    };\n};\n;\n// deflate with opts\nvar dopt = function (dat, opt, pre, post, st) {\n    if (!st) {\n        st = { l: 1 };\n        if (opt.dictionary) {\n            var dict = opt.dictionary.subarray(-32768);\n            var newDat = new u8(dict.length + dat.length);\n            newDat.set(dict);\n            newDat.set(dat, dict.length);\n            dat = newDat;\n            st.w = dict.length;\n        }\n    }\n    return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st);\n};\n// Walmart object spread\nvar mrg = function (a, b) {\n    var o = {};\n    for (var k in a)\n        o[k] = a[k];\n    for (var k in b)\n        o[k] = b[k];\n    return o;\n};\n// worker clone\n// This is possibly the craziest part of the entire codebase, despite how simple it may seem.\n// The only parameter to this function is a closure that returns an array of variables outside of the function scope.\n// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization.\n// We will return an object mapping of true variable name to value (basically, the current scope as a JS object).\n// The reason we can't just use the original variable names is minifiers mangling the toplevel scope.\n// This took me three weeks to figure out how to do.\nvar wcln = function (fn, fnStr, td) {\n    var dt = fn();\n    var st = fn.toString();\n    var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\\s+/g, '').split(',');\n    for (var i = 0; i < dt.length; ++i) {\n        var v = dt[i], k = ks[i];\n        if (typeof v == 'function') {\n            fnStr += ';' + k + '=';\n            var st_1 = v.toString();\n            if (v.prototype) {\n                // for global objects\n                if (st_1.indexOf('[native code]') != -1) {\n                    var spInd = st_1.indexOf(' ', 8) + 1;\n                    fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd));\n                }\n                else {\n                    fnStr += st_1;\n                    for (var t in v.prototype)\n                        fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString();\n                }\n            }\n            else\n                fnStr += st_1;\n        }\n        else\n            td[k] = v;\n    }\n    return fnStr;\n};\nvar ch = [];\n// clone bufs\nvar cbfs = function (v) {\n    var tl = [];\n    for (var k in v) {\n        if (v[k].buffer) {\n            tl.push((v[k] = new v[k].constructor(v[k])).buffer);\n        }\n    }\n    return tl;\n};\n// use a worker to execute code\nvar wrkr = function (fns, init, id, cb) {\n    if (!ch[id]) {\n        var fnStr = '', td_1 = {}, m = fns.length - 1;\n        for (var i = 0; i < m; ++i)\n            fnStr = wcln(fns[i], fnStr, td_1);\n        ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 };\n    }\n    var td = mrg({}, ch[id].e);\n    return wk(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb);\n};\n// base async inflate fn\nvar bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; };\nvar bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; };\n// gzip extra\nvar gze = function () { return [gzh, gzhl, wbytes, crc, crct]; };\n// gunzip extra\nvar guze = function () { return [gzs, gzl]; };\n// zlib extra\nvar zle = function () { return [zlh, wbytes, adler]; };\n// unzlib extra\nvar zule = function () { return [zls]; };\n// post buf\nvar pbf = function (msg) { return postMessage(msg, [msg.buffer]); };\n// get opts\nvar gopt = function (o) { return o && {\n    out: o.size && new u8(o.size),\n    dictionary: o.dictionary\n}; };\n// async helper\nvar cbify = function (dat, opts, fns, init, id, cb) {\n    var w = wrkr(fns, init, id, function (err, dat) {\n        w.terminate();\n        cb(err, dat);\n    });\n    w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []);\n    return function () { w.terminate(); };\n};\n// auto stream\nvar astrm = function (strm) {\n    strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); };\n    return function (ev) {\n        if (ev.data.length) {\n            strm.push(ev.data[0], ev.data[1]);\n            postMessage([ev.data[0].length]);\n        }\n        else\n            strm.flush();\n    };\n};\n// async stream attach\nvar astrmify = function (fns, strm, opts, init, id, flush, ext) {\n    var t;\n    var w = wrkr(fns, init, id, function (err, dat) {\n        if (err)\n            w.terminate(), strm.ondata.call(strm, err);\n        else if (!Array.isArray(dat))\n            ext(dat);\n        else if (dat.length == 1) {\n            strm.queuedSize -= dat[0];\n            if (strm.ondrain)\n                strm.ondrain(dat[0]);\n        }\n        else {\n            if (dat[1])\n                w.terminate();\n            strm.ondata.call(strm, err, dat[0], dat[1]);\n        }\n    });\n    w.postMessage(opts);\n    strm.queuedSize = 0;\n    strm.push = function (d, f) {\n        if (!strm.ondata)\n            err(5);\n        if (t)\n            strm.ondata(err(4, 0, 1), null, !!f);\n        strm.queuedSize += d.length;\n        w.postMessage([d, t = f], [d.buffer]);\n    };\n    strm.terminate = function () { w.terminate(); };\n    if (flush) {\n        strm.flush = function () { w.postMessage([]); };\n    }\n};\n// read 2 bytes\nvar b2 = function (d, b) { return d[b] | (d[b + 1] << 8); };\n// read 4 bytes\nvar b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; };\nvar b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); };\n// write bytes\nvar wbytes = function (d, b, v) {\n    for (; v; ++b)\n        d[b] = v, v >>>= 8;\n};\n// gzip header\nvar gzh = function (c, o) {\n    var fn = o.filename;\n    c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix\n    if (o.mtime != 0)\n        wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000));\n    if (fn) {\n        c[3] = 8;\n        for (var i = 0; i <= fn.length; ++i)\n            c[i + 10] = fn.charCodeAt(i);\n    }\n};\n// gzip footer: -8 to -4 = CRC, -4 to -0 is length\n// gzip start\nvar gzs = function (d) {\n    if (d[0] != 31 || d[1] != 139 || d[2] != 8)\n        err(6, 'invalid gzip data');\n    var flg = d[3];\n    var st = 10;\n    if (flg & 4)\n        st += (d[10] | d[11] << 8) + 2;\n    for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++])\n        ;\n    return st + (flg & 2);\n};\n// gzip length\nvar gzl = function (d) {\n    var l = d.length;\n    return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0;\n};\n// gzip header length\nvar gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); };\n// zlib header\nvar zlh = function (c, o) {\n    var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2;\n    c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32);\n    c[1] |= 31 - ((c[0] << 8) | c[1]) % 31;\n    if (o.dictionary) {\n        var h = adler();\n        h.p(o.dictionary);\n        wbytes(c, 2, h.d());\n    }\n};\n// zlib start\nvar zls = function (d, dict) {\n    if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31))\n        err(6, 'invalid zlib data');\n    if ((d[1] >> 5 & 1) == +!dict)\n        err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary');\n    return (d[1] >> 3 & 4) + 2;\n};\nfunction StrmOpt(opts, cb) {\n    if (typeof opts == 'function')\n        cb = opts, opts = {};\n    this.ondata = cb;\n    return opts;\n}\n/**\n * Streaming DEFLATE compression\n */\nvar Deflate = /*#__PURE__*/ (function () {\n    function Deflate(opts, cb) {\n        if (typeof opts == 'function')\n            cb = opts, opts = {};\n        this.ondata = cb;\n        this.o = opts || {};\n        this.s = { l: 0, i: 32768, w: 32768, z: 32768 };\n        // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev\n        // 98304 = 32768 (lookback) + 65536 (common chunk size)\n        this.b = new u8(98304);\n        if (this.o.dictionary) {\n            var dict = this.o.dictionary.subarray(-32768);\n            this.b.set(dict, 32768 - dict.length);\n            this.s.i = 32768 - dict.length;\n        }\n    }\n    Deflate.prototype.p = function (c, f) {\n        this.ondata(dopt(c, this.o, 0, 0, this.s), f);\n    };\n    /**\n     * Pushes a chunk to be deflated\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Deflate.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        if (this.s.l)\n            err(4);\n        var endLen = chunk.length + this.s.z;\n        if (endLen > this.b.length) {\n            if (endLen > 2 * this.b.length - 32768) {\n                var newBuf = new u8(endLen & -32768);\n                newBuf.set(this.b.subarray(0, this.s.z));\n                this.b = newBuf;\n            }\n            var split = this.b.length - this.s.z;\n            this.b.set(chunk.subarray(0, split), this.s.z);\n            this.s.z = this.b.length;\n            this.p(this.b, false);\n            this.b.set(this.b.subarray(-32768));\n            this.b.set(chunk.subarray(split), 32768);\n            this.s.z = chunk.length - split + 32768;\n            this.s.i = 32766, this.s.w = 32768;\n        }\n        else {\n            this.b.set(chunk, this.s.z);\n            this.s.z += chunk.length;\n        }\n        this.s.l = final & 1;\n        if (this.s.z > this.s.w + 8191 || final) {\n            this.p(this.b, final || false);\n            this.s.w = this.s.i, this.s.i -= 2;\n        }\n    };\n    /**\n     * Flushes buffered uncompressed data. Useful to immediately retrieve the\n     * deflated output for small inputs.\n     */\n    Deflate.prototype.flush = function () {\n        if (!this.ondata)\n            err(5);\n        if (this.s.l)\n            err(4);\n        this.p(this.b, false);\n        this.s.w = this.s.i, this.s.i -= 2;\n    };\n    return Deflate;\n}());\nexport { Deflate };\n/**\n * Asynchronous streaming DEFLATE compression\n */\nvar AsyncDeflate = /*#__PURE__*/ (function () {\n    function AsyncDeflate(opts, cb) {\n        astrmify([\n            bDflt,\n            function () { return [astrm, Deflate]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Deflate(ev.data);\n            onmessage = astrm(strm);\n        }, 6, 1);\n    }\n    return AsyncDeflate;\n}());\nexport { AsyncDeflate };\nexport function deflate(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bDflt,\n    ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb);\n}\n/**\n * Compresses data with DEFLATE without any wrapper\n * @param data The data to compress\n * @param opts The compression options\n * @returns The deflated version of the data\n */\nexport function deflateSync(data, opts) {\n    return dopt(data, opts || {}, 0, 0);\n}\n/**\n * Streaming DEFLATE decompression\n */\nvar Inflate = /*#__PURE__*/ (function () {\n    function Inflate(opts, cb) {\n        // no StrmOpt here to avoid adding to workerizer\n        if (typeof opts == 'function')\n            cb = opts, opts = {};\n        this.ondata = cb;\n        var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768);\n        this.s = { i: 0, b: dict ? dict.length : 0 };\n        this.o = new u8(32768);\n        this.p = new u8(0);\n        if (dict)\n            this.o.set(dict);\n    }\n    Inflate.prototype.e = function (c) {\n        if (!this.ondata)\n            err(5);\n        if (this.d)\n            err(4);\n        if (!this.p.length)\n            this.p = c;\n        else if (c.length) {\n            var n = new u8(this.p.length + c.length);\n            n.set(this.p), n.set(c, this.p.length), this.p = n;\n        }\n    };\n    Inflate.prototype.c = function (final) {\n        this.s.i = +(this.d = final || false);\n        var bts = this.s.b;\n        var dt = inflt(this.p, this.s, this.o);\n        this.ondata(slc(dt, bts, this.s.b), this.d);\n        this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length;\n        this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7;\n    };\n    /**\n     * Pushes a chunk to be inflated\n     * @param chunk The chunk to push\n     * @param final Whether this is the final chunk\n     */\n    Inflate.prototype.push = function (chunk, final) {\n        this.e(chunk), this.c(final);\n    };\n    return Inflate;\n}());\nexport { Inflate };\n/**\n * Asynchronous streaming DEFLATE decompression\n */\nvar AsyncInflate = /*#__PURE__*/ (function () {\n    function AsyncInflate(opts, cb) {\n        astrmify([\n            bInflt,\n            function () { return [astrm, Inflate]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Inflate(ev.data);\n            onmessage = astrm(strm);\n        }, 7, 0);\n    }\n    return AsyncInflate;\n}());\nexport { AsyncInflate };\nexport function inflate(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bInflt\n    ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb);\n}\n/**\n * Expands DEFLATE data with no wrapper\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function inflateSync(data, opts) {\n    return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);\n}\n// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize.\n/**\n * Streaming GZIP compression\n */\nvar Gzip = /*#__PURE__*/ (function () {\n    function Gzip(opts, cb) {\n        this.c = crc();\n        this.l = 0;\n        this.v = 1;\n        Deflate.call(this, opts, cb);\n    }\n    /**\n     * Pushes a chunk to be GZIPped\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Gzip.prototype.push = function (chunk, final) {\n        this.c.p(chunk);\n        this.l += chunk.length;\n        Deflate.prototype.push.call(this, chunk, final);\n    };\n    Gzip.prototype.p = function (c, f) {\n        var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s);\n        if (this.v)\n            gzh(raw, this.o), this.v = 0;\n        if (f)\n            wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l);\n        this.ondata(raw, f);\n    };\n    /**\n     * Flushes buffered uncompressed data. Useful to immediately retrieve the\n     * GZIPped output for small inputs.\n     */\n    Gzip.prototype.flush = function () {\n        Deflate.prototype.flush.call(this);\n    };\n    return Gzip;\n}());\nexport { Gzip };\n/**\n * Asynchronous streaming GZIP compression\n */\nvar AsyncGzip = /*#__PURE__*/ (function () {\n    function AsyncGzip(opts, cb) {\n        astrmify([\n            bDflt,\n            gze,\n            function () { return [astrm, Deflate, Gzip]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Gzip(ev.data);\n            onmessage = astrm(strm);\n        }, 8, 1);\n    }\n    return AsyncGzip;\n}());\nexport { AsyncGzip };\nexport function gzip(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bDflt,\n        gze,\n        function () { return [gzipSync]; }\n    ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb);\n}\n/**\n * Compresses data with GZIP\n * @param data The data to compress\n * @param opts The compression options\n * @returns The gzipped version of the data\n */\nexport function gzipSync(data, opts) {\n    if (!opts)\n        opts = {};\n    var c = crc(), l = data.length;\n    c.p(data);\n    var d = dopt(data, opts, gzhl(opts), 8), s = d.length;\n    return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d;\n}\n/**\n * Streaming single or multi-member GZIP decompression\n */\nvar Gunzip = /*#__PURE__*/ (function () {\n    function Gunzip(opts, cb) {\n        this.v = 1;\n        this.r = 0;\n        Inflate.call(this, opts, cb);\n    }\n    /**\n     * Pushes a chunk to be GUNZIPped\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Gunzip.prototype.push = function (chunk, final) {\n        Inflate.prototype.e.call(this, chunk);\n        this.r += chunk.length;\n        if (this.v) {\n            var p = this.p.subarray(this.v - 1);\n            var s = p.length > 3 ? gzs(p) : 4;\n            if (s > p.length) {\n                if (!final)\n                    return;\n            }\n            else if (this.v > 1 && this.onmember) {\n                this.onmember(this.r - p.length);\n            }\n            this.p = p.subarray(s), this.v = 0;\n        }\n        // necessary to prevent TS from using the closure value\n        // This allows for workerization to function correctly\n        Inflate.prototype.c.call(this, final);\n        // process concatenated GZIP\n        if (this.s.f && !this.s.l && !final) {\n            this.v = shft(this.s.p) + 9;\n            this.s = { i: 0 };\n            this.o = new u8(0);\n            this.push(new u8(0), final);\n        }\n    };\n    return Gunzip;\n}());\nexport { Gunzip };\n/**\n * Asynchronous streaming single or multi-member GZIP decompression\n */\nvar AsyncGunzip = /*#__PURE__*/ (function () {\n    function AsyncGunzip(opts, cb) {\n        var _this = this;\n        astrmify([\n            bInflt,\n            guze,\n            function () { return [astrm, Inflate, Gunzip]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Gunzip(ev.data);\n            strm.onmember = function (offset) { return postMessage(offset); };\n            onmessage = astrm(strm);\n        }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); });\n    }\n    return AsyncGunzip;\n}());\nexport { AsyncGunzip };\nexport function gunzip(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bInflt,\n        guze,\n        function () { return [gunzipSync]; }\n    ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb);\n}\n/**\n * Expands GZIP data\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function gunzipSync(data, opts) {\n    var st = gzs(data);\n    if (st + 8 > data.length)\n        err(6, 'invalid gzip data');\n    return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);\n}\n/**\n * Streaming Zlib compression\n */\nvar Zlib = /*#__PURE__*/ (function () {\n    function Zlib(opts, cb) {\n        this.c = adler();\n        this.v = 1;\n        Deflate.call(this, opts, cb);\n    }\n    /**\n     * Pushes a chunk to be zlibbed\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Zlib.prototype.push = function (chunk, final) {\n        this.c.p(chunk);\n        Deflate.prototype.push.call(this, chunk, final);\n    };\n    Zlib.prototype.p = function (c, f) {\n        var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s);\n        if (this.v)\n            zlh(raw, this.o), this.v = 0;\n        if (f)\n            wbytes(raw, raw.length - 4, this.c.d());\n        this.ondata(raw, f);\n    };\n    /**\n     * Flushes buffered uncompressed data. Useful to immediately retrieve the\n     * zlibbed output for small inputs.\n     */\n    Zlib.prototype.flush = function () {\n        Deflate.prototype.flush.call(this);\n    };\n    return Zlib;\n}());\nexport { Zlib };\n/**\n * Asynchronous streaming Zlib compression\n */\nvar AsyncZlib = /*#__PURE__*/ (function () {\n    function AsyncZlib(opts, cb) {\n        astrmify([\n            bDflt,\n            zle,\n            function () { return [astrm, Deflate, Zlib]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Zlib(ev.data);\n            onmessage = astrm(strm);\n        }, 10, 1);\n    }\n    return AsyncZlib;\n}());\nexport { AsyncZlib };\nexport function zlib(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bDflt,\n        zle,\n        function () { return [zlibSync]; }\n    ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb);\n}\n/**\n * Compress data with Zlib\n * @param data The data to compress\n * @param opts The compression options\n * @returns The zlib-compressed version of the data\n */\nexport function zlibSync(data, opts) {\n    if (!opts)\n        opts = {};\n    var a = adler();\n    a.p(data);\n    var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4);\n    return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d;\n}\n/**\n * Streaming Zlib decompression\n */\nvar Unzlib = /*#__PURE__*/ (function () {\n    function Unzlib(opts, cb) {\n        Inflate.call(this, opts, cb);\n        this.v = opts && opts.dictionary ? 2 : 1;\n    }\n    /**\n     * Pushes a chunk to be unzlibbed\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Unzlib.prototype.push = function (chunk, final) {\n        Inflate.prototype.e.call(this, chunk);\n        if (this.v) {\n            if (this.p.length < 6 && !final)\n                return;\n            this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0;\n        }\n        if (final) {\n            if (this.p.length < 4)\n                err(6, 'invalid zlib data');\n            this.p = this.p.subarray(0, -4);\n        }\n        // necessary to prevent TS from using the closure value\n        // This allows for workerization to function correctly\n        Inflate.prototype.c.call(this, final);\n    };\n    return Unzlib;\n}());\nexport { Unzlib };\n/**\n * Asynchronous streaming Zlib decompression\n */\nvar AsyncUnzlib = /*#__PURE__*/ (function () {\n    function AsyncUnzlib(opts, cb) {\n        astrmify([\n            bInflt,\n            zule,\n            function () { return [astrm, Inflate, Unzlib]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Unzlib(ev.data);\n            onmessage = astrm(strm);\n        }, 11, 0);\n    }\n    return AsyncUnzlib;\n}());\nexport { AsyncUnzlib };\nexport function unzlib(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bInflt,\n        zule,\n        function () { return [unzlibSync]; }\n    ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb);\n}\n/**\n * Expands Zlib data\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function unzlibSync(data, opts) {\n    return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary);\n}\n// Default algorithm for compression (used because having a known output size allows faster decompression)\nexport { gzip as compress, AsyncGzip as AsyncCompress };\nexport { gzipSync as compressSync, Gzip as Compress };\n/**\n * Streaming GZIP, Zlib, or raw DEFLATE decompression\n */\nvar Decompress = /*#__PURE__*/ (function () {\n    function Decompress(opts, cb) {\n        this.o = StrmOpt.call(this, opts, cb) || {};\n        this.G = Gunzip;\n        this.I = Inflate;\n        this.Z = Unzlib;\n    }\n    // init substream\n    // overriden by AsyncDecompress\n    Decompress.prototype.i = function () {\n        var _this = this;\n        this.s.ondata = function (dat, final) {\n            _this.ondata(dat, final);\n        };\n    };\n    /**\n     * Pushes a chunk to be decompressed\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Decompress.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        if (!this.s) {\n            if (this.p && this.p.length) {\n                var n = new u8(this.p.length + chunk.length);\n                n.set(this.p), n.set(chunk, this.p.length);\n            }\n            else\n                this.p = chunk;\n            if (this.p.length > 2) {\n                this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8)\n                    ? new this.G(this.o)\n                    : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31))\n                        ? new this.I(this.o)\n                        : new this.Z(this.o);\n                this.i();\n                this.s.push(this.p, final);\n                this.p = null;\n            }\n        }\n        else\n            this.s.push(chunk, final);\n    };\n    return Decompress;\n}());\nexport { Decompress };\n/**\n * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression\n */\nvar AsyncDecompress = /*#__PURE__*/ (function () {\n    function AsyncDecompress(opts, cb) {\n        Decompress.call(this, opts, cb);\n        this.queuedSize = 0;\n        this.G = AsyncGunzip;\n        this.I = AsyncInflate;\n        this.Z = AsyncUnzlib;\n    }\n    AsyncDecompress.prototype.i = function () {\n        var _this = this;\n        this.s.ondata = function (err, dat, final) {\n            _this.ondata(err, dat, final);\n        };\n        this.s.ondrain = function (size) {\n            _this.queuedSize -= size;\n            if (_this.ondrain)\n                _this.ondrain(size);\n        };\n    };\n    /**\n     * Pushes a chunk to be decompressed\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    AsyncDecompress.prototype.push = function (chunk, final) {\n        this.queuedSize += chunk.length;\n        Decompress.prototype.push.call(this, chunk, final);\n    };\n    return AsyncDecompress;\n}());\nexport { AsyncDecompress };\nexport function decompress(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return (data[0] == 31 && data[1] == 139 && data[2] == 8)\n        ? gunzip(data, opts, cb)\n        : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31))\n            ? inflate(data, opts, cb)\n            : unzlib(data, opts, cb);\n}\n/**\n * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function decompressSync(data, opts) {\n    return (data[0] == 31 && data[1] == 139 && data[2] == 8)\n        ? gunzipSync(data, opts)\n        : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31))\n            ? inflateSync(data, opts)\n            : unzlibSync(data, opts);\n}\n// flatten a directory structure\nvar fltn = function (d, p, t, o) {\n    for (var k in d) {\n        var val = d[k], n = p + k, op = o;\n        if (Array.isArray(val))\n            op = mrg(o, val[1]), val = val[0];\n        if (val instanceof u8)\n            t[n] = [val, op];\n        else {\n            t[n += '/'] = [new u8(0), op];\n            fltn(val, n, t, o);\n        }\n    }\n};\n// text encoder\nvar te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder();\n// text decoder\nvar td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder();\n// text decoder stream\nvar tds = 0;\ntry {\n    td.decode(et, { stream: true });\n    tds = 1;\n}\ncatch (e) { }\n// decode UTF8\nvar dutf8 = function (d) {\n    for (var r = '', i = 0;;) {\n        var c = d[i++];\n        var eb = (c > 127) + (c > 223) + (c > 239);\n        if (i + eb > d.length)\n            return { s: r, r: slc(d, i - 1) };\n        if (!eb)\n            r += String.fromCharCode(c);\n        else if (eb == 3) {\n            c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536,\n                r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023));\n        }\n        else if (eb & 1)\n            r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63));\n        else\n            r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63));\n    }\n};\n/**\n * Streaming UTF-8 decoding\n */\nvar DecodeUTF8 = /*#__PURE__*/ (function () {\n    /**\n     * Creates a UTF-8 decoding stream\n     * @param cb The callback to call whenever data is decoded\n     */\n    function DecodeUTF8(cb) {\n        this.ondata = cb;\n        if (tds)\n            this.t = new TextDecoder();\n        else\n            this.p = et;\n    }\n    /**\n     * Pushes a chunk to be decoded from UTF-8 binary\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    DecodeUTF8.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        final = !!final;\n        if (this.t) {\n            this.ondata(this.t.decode(chunk, { stream: true }), final);\n            if (final) {\n                if (this.t.decode().length)\n                    err(8);\n                this.t = null;\n            }\n            return;\n        }\n        if (!this.p)\n            err(4);\n        var dat = new u8(this.p.length + chunk.length);\n        dat.set(this.p);\n        dat.set(chunk, this.p.length);\n        var _a = dutf8(dat), s = _a.s, r = _a.r;\n        if (final) {\n            if (r.length)\n                err(8);\n            this.p = null;\n        }\n        else\n            this.p = r;\n        this.ondata(s, final);\n    };\n    return DecodeUTF8;\n}());\nexport { DecodeUTF8 };\n/**\n * Streaming UTF-8 encoding\n */\nvar EncodeUTF8 = /*#__PURE__*/ (function () {\n    /**\n     * Creates a UTF-8 decoding stream\n     * @param cb The callback to call whenever data is encoded\n     */\n    function EncodeUTF8(cb) {\n        this.ondata = cb;\n    }\n    /**\n     * Pushes a chunk to be encoded to UTF-8\n     * @param chunk The string data to push\n     * @param final Whether this is the last chunk\n     */\n    EncodeUTF8.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        if (this.d)\n            err(4);\n        this.ondata(strToU8(chunk), this.d = final || false);\n    };\n    return EncodeUTF8;\n}());\nexport { EncodeUTF8 };\n/**\n * Converts a string into a Uint8Array for use with compression/decompression methods\n * @param str The string to encode\n * @param latin1 Whether or not to interpret the data as Latin-1. This should\n *               not need to be true unless decoding a binary string.\n * @returns The string encoded in UTF-8/Latin-1 binary\n */\nexport function strToU8(str, latin1) {\n    if (latin1) {\n        var ar_1 = new u8(str.length);\n        for (var i = 0; i < str.length; ++i)\n            ar_1[i] = str.charCodeAt(i);\n        return ar_1;\n    }\n    if (te)\n        return te.encode(str);\n    var l = str.length;\n    var ar = new u8(str.length + (str.length >> 1));\n    var ai = 0;\n    var w = function (v) { ar[ai++] = v; };\n    for (var i = 0; i < l; ++i) {\n        if (ai + 5 > ar.length) {\n            var n = new u8(ai + 8 + ((l - i) << 1));\n            n.set(ar);\n            ar = n;\n        }\n        var c = str.charCodeAt(i);\n        if (c < 128 || latin1)\n            w(c);\n        else if (c < 2048)\n            w(192 | (c >> 6)), w(128 | (c & 63));\n        else if (c > 55295 && c < 57344)\n            c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023),\n                w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63));\n        else\n            w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63));\n    }\n    return slc(ar, 0, ai);\n}\n/**\n * Converts a Uint8Array to a string\n * @param dat The data to decode to string\n * @param latin1 Whether or not to interpret the data as Latin-1. This should\n *               not need to be true unless encoding to binary string.\n * @returns The original UTF-8/Latin-1 string\n */\nexport function strFromU8(dat, latin1) {\n    if (latin1) {\n        var r = '';\n        for (var i = 0; i < dat.length; i += 16384)\n            r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));\n        return r;\n    }\n    else if (td) {\n        return td.decode(dat);\n    }\n    else {\n        var _a = dutf8(dat), s = _a.s, r = _a.r;\n        if (r.length)\n            err(8);\n        return s;\n    }\n}\n;\n// deflate bit flag\nvar dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; };\n// skip local zip header\nvar slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); };\n// read zip header\nvar zh = function (d, b, z) {\n    var fnl = b2(d, b + 28), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20);\n    var _a = z && bs == 4294967295 ? z64e(d, es) : [bs, b4(d, b + 24), b4(d, b + 42)], sc = _a[0], su = _a[1], off = _a[2];\n    return [b2(d, b + 10), sc, su, fn, es + b2(d, b + 30) + b2(d, b + 32), off];\n};\n// read zip64 extra field\nvar z64e = function (d, b) {\n    for (; b2(d, b) != 1; b += 4 + b2(d, b + 2))\n        ;\n    return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];\n};\n// extra field length\nvar exfl = function (ex) {\n    var le = 0;\n    if (ex) {\n        for (var k in ex) {\n            var l = ex[k].length;\n            if (l > 65535)\n                err(9);\n            le += l + 4;\n        }\n    }\n    return le;\n};\n// write zip header\nvar wzh = function (d, b, f, fn, u, c, ce, co) {\n    var fl = fn.length, ex = f.extra, col = co && co.length;\n    var exl = exfl(ex);\n    wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4;\n    if (ce != null)\n        d[b++] = 20, d[b++] = f.os;\n    d[b] = 20, b += 2; // spec compliance? what's that?\n    d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8;\n    d[b++] = f.compression & 255, d[b++] = f.compression >> 8;\n    var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;\n    if (y < 0 || y > 119)\n        err(10);\n    wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4;\n    if (c != -1) {\n        wbytes(d, b, f.crc);\n        wbytes(d, b + 4, c < 0 ? -c - 2 : c);\n        wbytes(d, b + 8, f.size);\n    }\n    wbytes(d, b + 12, fl);\n    wbytes(d, b + 14, exl), b += 16;\n    if (ce != null) {\n        wbytes(d, b, col);\n        wbytes(d, b + 6, f.attrs);\n        wbytes(d, b + 10, ce), b += 14;\n    }\n    d.set(fn, b);\n    b += fl;\n    if (exl) {\n        for (var k in ex) {\n            var exf = ex[k], l = exf.length;\n            wbytes(d, b, +k);\n            wbytes(d, b + 2, l);\n            d.set(exf, b + 4), b += 4 + l;\n        }\n    }\n    if (col)\n        d.set(co, b), b += col;\n    return b;\n};\n// write zip footer (end of central directory)\nvar wzf = function (o, b, c, d, e) {\n    wbytes(o, b, 0x6054B50); // skip disk\n    wbytes(o, b + 8, c);\n    wbytes(o, b + 10, c);\n    wbytes(o, b + 12, d);\n    wbytes(o, b + 16, e);\n};\n/**\n * A pass-through stream to keep data uncompressed in a ZIP archive.\n */\nvar ZipPassThrough = /*#__PURE__*/ (function () {\n    /**\n     * Creates a pass-through stream that can be added to ZIP archives\n     * @param filename The filename to associate with this data stream\n     */\n    function ZipPassThrough(filename) {\n        this.filename = filename;\n        this.c = crc();\n        this.size = 0;\n        this.compression = 0;\n    }\n    /**\n     * Processes a chunk and pushes to the output stream. You can override this\n     * method in a subclass for custom behavior, but by default this passes\n     * the data through. You must call this.ondata(err, chunk, final) at some\n     * point in this method.\n     * @param chunk The chunk to process\n     * @param final Whether this is the last chunk\n     */\n    ZipPassThrough.prototype.process = function (chunk, final) {\n        this.ondata(null, chunk, final);\n    };\n    /**\n     * Pushes a chunk to be added. If you are subclassing this with a custom\n     * compression algorithm, note that you must push data from the source\n     * file only, pre-compression.\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    ZipPassThrough.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        this.c.p(chunk);\n        this.size += chunk.length;\n        if (final)\n            this.crc = this.c.d();\n        this.process(chunk, final || false);\n    };\n    return ZipPassThrough;\n}());\nexport { ZipPassThrough };\n// I don't extend because TypeScript extension adds 1kB of runtime bloat\n/**\n * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate\n * for better performance\n */\nvar ZipDeflate = /*#__PURE__*/ (function () {\n    /**\n     * Creates a DEFLATE stream that can be added to ZIP archives\n     * @param filename The filename to associate with this data stream\n     * @param opts The compression options\n     */\n    function ZipDeflate(filename, opts) {\n        var _this = this;\n        if (!opts)\n            opts = {};\n        ZipPassThrough.call(this, filename);\n        this.d = new Deflate(opts, function (dat, final) {\n            _this.ondata(null, dat, final);\n        });\n        this.compression = 8;\n        this.flag = dbf(opts.level);\n    }\n    ZipDeflate.prototype.process = function (chunk, final) {\n        try {\n            this.d.push(chunk, final);\n        }\n        catch (e) {\n            this.ondata(e, null, final);\n        }\n    };\n    /**\n     * Pushes a chunk to be deflated\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    ZipDeflate.prototype.push = function (chunk, final) {\n        ZipPassThrough.prototype.push.call(this, chunk, final);\n    };\n    return ZipDeflate;\n}());\nexport { ZipDeflate };\n/**\n * Asynchronous streaming DEFLATE compression for ZIP archives\n */\nvar AsyncZipDeflate = /*#__PURE__*/ (function () {\n    /**\n     * Creates an asynchronous DEFLATE stream that can be added to ZIP archives\n     * @param filename The filename to associate with this data stream\n     * @param opts The compression options\n     */\n    function AsyncZipDeflate(filename, opts) {\n        var _this = this;\n        if (!opts)\n            opts = {};\n        ZipPassThrough.call(this, filename);\n        this.d = new AsyncDeflate(opts, function (err, dat, final) {\n            _this.ondata(err, dat, final);\n        });\n        this.compression = 8;\n        this.flag = dbf(opts.level);\n        this.terminate = this.d.terminate;\n    }\n    AsyncZipDeflate.prototype.process = function (chunk, final) {\n        this.d.push(chunk, final);\n    };\n    /**\n     * Pushes a chunk to be deflated\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    AsyncZipDeflate.prototype.push = function (chunk, final) {\n        ZipPassThrough.prototype.push.call(this, chunk, final);\n    };\n    return AsyncZipDeflate;\n}());\nexport { AsyncZipDeflate };\n// TODO: Better tree shaking\n/**\n * A zippable archive to which files can incrementally be added\n */\nvar Zip = /*#__PURE__*/ (function () {\n    /**\n     * Creates an empty ZIP archive to which files can be added\n     * @param cb The callback to call whenever data for the generated ZIP archive\n     *           is available\n     */\n    function Zip(cb) {\n        this.ondata = cb;\n        this.u = [];\n        this.d = 1;\n    }\n    /**\n     * Adds a file to the ZIP archive\n     * @param file The file stream to add\n     */\n    Zip.prototype.add = function (file) {\n        var _this = this;\n        if (!this.ondata)\n            err(5);\n        // finishing or finished\n        if (this.d & 2)\n            this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false);\n        else {\n            var f = strToU8(file.filename), fl_1 = f.length;\n            var com = file.comment, o = com && strToU8(com);\n            var u = fl_1 != file.filename.length || (o && (com.length != o.length));\n            var hl_1 = fl_1 + exfl(file.extra) + 30;\n            if (fl_1 > 65535)\n                this.ondata(err(11, 0, 1), null, false);\n            var header = new u8(hl_1);\n            wzh(header, 0, file, f, u, -1);\n            var chks_1 = [header];\n            var pAll_1 = function () {\n                for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) {\n                    var chk = chks_2[_i];\n                    _this.ondata(null, chk, false);\n                }\n                chks_1 = [];\n            };\n            var tr_1 = this.d;\n            this.d = 0;\n            var ind_1 = this.u.length;\n            var uf_1 = mrg(file, {\n                f: f,\n                u: u,\n                o: o,\n                t: function () {\n                    if (file.terminate)\n                        file.terminate();\n                },\n                r: function () {\n                    pAll_1();\n                    if (tr_1) {\n                        var nxt = _this.u[ind_1 + 1];\n                        if (nxt)\n                            nxt.r();\n                        else\n                            _this.d = 1;\n                    }\n                    tr_1 = 1;\n                }\n            });\n            var cl_1 = 0;\n            file.ondata = function (err, dat, final) {\n                if (err) {\n                    _this.ondata(err, dat, final);\n                    _this.terminate();\n                }\n                else {\n                    cl_1 += dat.length;\n                    chks_1.push(dat);\n                    if (final) {\n                        var dd = new u8(16);\n                        wbytes(dd, 0, 0x8074B50);\n                        wbytes(dd, 4, file.crc);\n                        wbytes(dd, 8, cl_1);\n                        wbytes(dd, 12, file.size);\n                        chks_1.push(dd);\n                        uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size;\n                        if (tr_1)\n                            uf_1.r();\n                        tr_1 = 1;\n                    }\n                    else if (tr_1)\n                        pAll_1();\n                }\n            };\n            this.u.push(uf_1);\n        }\n    };\n    /**\n     * Ends the process of adding files and prepares to emit the final chunks.\n     * This *must* be called after adding all desired files for the resulting\n     * ZIP file to work properly.\n     */\n    Zip.prototype.end = function () {\n        var _this = this;\n        if (this.d & 2) {\n            this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true);\n            return;\n        }\n        if (this.d)\n            this.e();\n        else\n            this.u.push({\n                r: function () {\n                    if (!(_this.d & 1))\n                        return;\n                    _this.u.splice(-1, 1);\n                    _this.e();\n                },\n                t: function () { }\n            });\n        this.d = 3;\n    };\n    Zip.prototype.e = function () {\n        var bt = 0, l = 0, tl = 0;\n        for (var _i = 0, _a = this.u; _i < _a.length; _i++) {\n            var f = _a[_i];\n            tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0);\n        }\n        var out = new u8(tl + 22);\n        for (var _b = 0, _c = this.u; _b < _c.length; _b++) {\n            var f = _c[_b];\n            wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o);\n            bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b;\n        }\n        wzf(out, bt, this.u.length, tl, l);\n        this.ondata(null, out, true);\n        this.d = 2;\n    };\n    /**\n     * A method to terminate any internal workers used by the stream. Subsequent\n     * calls to add() will fail.\n     */\n    Zip.prototype.terminate = function () {\n        for (var _i = 0, _a = this.u; _i < _a.length; _i++) {\n            var f = _a[_i];\n            f.t();\n        }\n        this.d = 2;\n    };\n    return Zip;\n}());\nexport { Zip };\nexport function zip(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    var r = {};\n    fltn(data, '', r, opts);\n    var k = Object.keys(r);\n    var lft = k.length, o = 0, tot = 0;\n    var slft = lft, files = new Array(lft);\n    var term = [];\n    var tAll = function () {\n        for (var i = 0; i < term.length; ++i)\n            term[i]();\n    };\n    var cbd = function (a, b) {\n        mt(function () { cb(a, b); });\n    };\n    mt(function () { cbd = cb; });\n    var cbf = function () {\n        var out = new u8(tot + 22), oe = o, cdl = tot - o;\n        tot = 0;\n        for (var i = 0; i < slft; ++i) {\n            var f = files[i];\n            try {\n                var l = f.c.length;\n                wzh(out, tot, f, f.f, f.u, l);\n                var badd = 30 + f.f.length + exfl(f.extra);\n                var loc = tot + badd;\n                out.set(f.c, loc);\n                wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l;\n            }\n            catch (e) {\n                return cbd(e, null);\n            }\n        }\n        wzf(out, o, files.length, cdl, oe);\n        cbd(null, out);\n    };\n    if (!lft)\n        cbf();\n    var _loop_1 = function (i) {\n        var fn = k[i];\n        var _a = r[fn], file = _a[0], p = _a[1];\n        var c = crc(), size = file.length;\n        c.p(file);\n        var f = strToU8(fn), s = f.length;\n        var com = p.comment, m = com && strToU8(com), ms = m && m.length;\n        var exl = exfl(p.extra);\n        var compression = p.level == 0 ? 0 : 8;\n        var cbl = function (e, d) {\n            if (e) {\n                tAll();\n                cbd(e, null);\n            }\n            else {\n                var l = d.length;\n                files[i] = mrg(p, {\n                    size: size,\n                    crc: c.d(),\n                    c: d,\n                    f: f,\n                    m: m,\n                    u: s != fn.length || (m && (com.length != ms)),\n                    compression: compression\n                });\n                o += 30 + s + exl + l;\n                tot += 76 + 2 * (s + exl) + (ms || 0) + l;\n                if (!--lft)\n                    cbf();\n            }\n        };\n        if (s > 65535)\n            cbl(err(11, 0, 1), null);\n        if (!compression)\n            cbl(null, file);\n        else if (size < 160000) {\n            try {\n                cbl(null, deflateSync(file, p));\n            }\n            catch (e) {\n                cbl(e, null);\n            }\n        }\n        else\n            term.push(deflate(file, p, cbl));\n    };\n    // Cannot use lft because it can decrease\n    for (var i = 0; i < slft; ++i) {\n        _loop_1(i);\n    }\n    return tAll;\n}\n/**\n * Synchronously creates a ZIP file. Prefer using `zip` for better performance\n * with more than one file.\n * @param data The directory structure for the ZIP archive\n * @param opts The main options, merged with per-file options\n * @returns The generated ZIP archive\n */\nexport function zipSync(data, opts) {\n    if (!opts)\n        opts = {};\n    var r = {};\n    var files = [];\n    fltn(data, '', r, opts);\n    var o = 0;\n    var tot = 0;\n    for (var fn in r) {\n        var _a = r[fn], file = _a[0], p = _a[1];\n        var compression = p.level == 0 ? 0 : 8;\n        var f = strToU8(fn), s = f.length;\n        var com = p.comment, m = com && strToU8(com), ms = m && m.length;\n        var exl = exfl(p.extra);\n        if (s > 65535)\n            err(11);\n        var d = compression ? deflateSync(file, p) : file, l = d.length;\n        var c = crc();\n        c.p(file);\n        files.push(mrg(p, {\n            size: file.length,\n            crc: c.d(),\n            c: d,\n            f: f,\n            m: m,\n            u: s != fn.length || (m && (com.length != ms)),\n            o: o,\n            compression: compression\n        }));\n        o += 30 + s + exl + l;\n        tot += 76 + 2 * (s + exl) + (ms || 0) + l;\n    }\n    var out = new u8(tot + 22), oe = o, cdl = tot - o;\n    for (var i = 0; i < files.length; ++i) {\n        var f = files[i];\n        wzh(out, f.o, f, f.f, f.u, f.c.length);\n        var badd = 30 + f.f.length + exfl(f.extra);\n        out.set(f.c, f.o + badd);\n        wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);\n    }\n    wzf(out, o, files.length, cdl, oe);\n    return out;\n}\n/**\n * Streaming pass-through decompression for ZIP archives\n */\nvar UnzipPassThrough = /*#__PURE__*/ (function () {\n    function UnzipPassThrough() {\n    }\n    UnzipPassThrough.prototype.push = function (data, final) {\n        this.ondata(null, data, final);\n    };\n    UnzipPassThrough.compression = 0;\n    return UnzipPassThrough;\n}());\nexport { UnzipPassThrough };\n/**\n * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for\n * better performance.\n */\nvar UnzipInflate = /*#__PURE__*/ (function () {\n    /**\n     * Creates a DEFLATE decompression that can be used in ZIP archives\n     */\n    function UnzipInflate() {\n        var _this = this;\n        this.i = new Inflate(function (dat, final) {\n            _this.ondata(null, dat, final);\n        });\n    }\n    UnzipInflate.prototype.push = function (data, final) {\n        try {\n            this.i.push(data, final);\n        }\n        catch (e) {\n            this.ondata(e, null, final);\n        }\n    };\n    UnzipInflate.compression = 8;\n    return UnzipInflate;\n}());\nexport { UnzipInflate };\n/**\n * Asynchronous streaming DEFLATE decompression for ZIP archives\n */\nvar AsyncUnzipInflate = /*#__PURE__*/ (function () {\n    /**\n     * Creates a DEFLATE decompression that can be used in ZIP archives\n     */\n    function AsyncUnzipInflate(_, sz) {\n        var _this = this;\n        if (sz < 320000) {\n            this.i = new Inflate(function (dat, final) {\n                _this.ondata(null, dat, final);\n            });\n        }\n        else {\n            this.i = new AsyncInflate(function (err, dat, final) {\n                _this.ondata(err, dat, final);\n            });\n            this.terminate = this.i.terminate;\n        }\n    }\n    AsyncUnzipInflate.prototype.push = function (data, final) {\n        if (this.i.terminate)\n            data = slc(data, 0);\n        this.i.push(data, final);\n    };\n    AsyncUnzipInflate.compression = 8;\n    return AsyncUnzipInflate;\n}());\nexport { AsyncUnzipInflate };\n/**\n * A ZIP archive decompression stream that emits files as they are discovered\n */\nvar Unzip = /*#__PURE__*/ (function () {\n    /**\n     * Creates a ZIP decompression stream\n     * @param cb The callback to call whenever a file in the ZIP archive is found\n     */\n    function Unzip(cb) {\n        this.onfile = cb;\n        this.k = [];\n        this.o = {\n            0: UnzipPassThrough\n        };\n        this.p = et;\n    }\n    /**\n     * Pushes a chunk to be unzipped\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Unzip.prototype.push = function (chunk, final) {\n        var _this = this;\n        if (!this.onfile)\n            err(5);\n        if (!this.p)\n            err(4);\n        if (this.c > 0) {\n            var len = Math.min(this.c, chunk.length);\n            var toAdd = chunk.subarray(0, len);\n            this.c -= len;\n            if (this.d)\n                this.d.push(toAdd, !this.c);\n            else\n                this.k[0].push(toAdd);\n            chunk = chunk.subarray(len);\n            if (chunk.length)\n                return this.push(chunk, final);\n        }\n        else {\n            var f = 0, i = 0, is = void 0, buf = void 0;\n            if (!this.p.length)\n                buf = chunk;\n            else if (!chunk.length)\n                buf = this.p;\n            else {\n                buf = new u8(this.p.length + chunk.length);\n                buf.set(this.p), buf.set(chunk, this.p.length);\n            }\n            var l = buf.length, oc = this.c, add = oc && this.d;\n            var _loop_2 = function () {\n                var _a;\n                var sig = b4(buf, i);\n                if (sig == 0x4034B50) {\n                    f = 1, is = i;\n                    this_1.d = null;\n                    this_1.c = 0;\n                    var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28);\n                    if (l > i + 30 + fnl + es) {\n                        var chks_3 = [];\n                        this_1.k.unshift(chks_3);\n                        f = 2;\n                        var sc_1 = b4(buf, i + 18), su_1 = b4(buf, i + 22);\n                        var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u);\n                        if (sc_1 == 4294967295) {\n                            _a = dd ? [-2] : z64e(buf, i), sc_1 = _a[0], su_1 = _a[1];\n                        }\n                        else if (dd)\n                            sc_1 = -1;\n                        i += es;\n                        this_1.c = sc_1;\n                        var d_1;\n                        var file_1 = {\n                            name: fn_1,\n                            compression: cmp_1,\n                            start: function () {\n                                if (!file_1.ondata)\n                                    err(5);\n                                if (!sc_1)\n                                    file_1.ondata(null, et, true);\n                                else {\n                                    var ctr = _this.o[cmp_1];\n                                    if (!ctr)\n                                        file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false);\n                                    d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1);\n                                    d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); };\n                                    for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) {\n                                        var dat = chks_4[_i];\n                                        d_1.push(dat, false);\n                                    }\n                                    if (_this.k[0] == chks_3 && _this.c)\n                                        _this.d = d_1;\n                                    else\n                                        d_1.push(et, true);\n                                }\n                            },\n                            terminate: function () {\n                                if (d_1 && d_1.terminate)\n                                    d_1.terminate();\n                            }\n                        };\n                        if (sc_1 >= 0)\n                            file_1.size = sc_1, file_1.originalSize = su_1;\n                        this_1.onfile(file_1);\n                    }\n                    return \"break\";\n                }\n                else if (oc) {\n                    if (sig == 0x8074B50) {\n                        is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0;\n                        return \"break\";\n                    }\n                    else if (sig == 0x2014B50) {\n                        is = i -= 4, f = 3, this_1.c = 0;\n                        return \"break\";\n                    }\n                }\n            };\n            var this_1 = this;\n            for (; i < l - 4; ++i) {\n                var state_1 = _loop_2();\n                if (state_1 === \"break\")\n                    break;\n            }\n            this.p = et;\n            if (oc < 0) {\n                var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i);\n                if (add)\n                    add.push(dat, !!f);\n                else\n                    this.k[+(f == 2)].push(dat);\n            }\n            if (f & 2)\n                return this.push(buf.subarray(i), final);\n            this.p = buf.subarray(i);\n        }\n        if (final) {\n            if (this.c)\n                err(13);\n            this.p = null;\n        }\n    };\n    /**\n     * Registers a decoder with the stream, allowing for files compressed with\n     * the compression type provided to be expanded correctly\n     * @param decoder The decoder constructor\n     */\n    Unzip.prototype.register = function (decoder) {\n        this.o[decoder.compression] = decoder;\n    };\n    return Unzip;\n}());\nexport { Unzip };\nvar mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); };\nexport function unzip(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    var term = [];\n    var tAll = function () {\n        for (var i = 0; i < term.length; ++i)\n            term[i]();\n    };\n    var files = {};\n    var cbd = function (a, b) {\n        mt(function () { cb(a, b); });\n    };\n    mt(function () { cbd = cb; });\n    var e = data.length - 22;\n    for (; b4(data, e) != 0x6054B50; --e) {\n        if (!e || data.length - e > 65558) {\n            cbd(err(13, 0, 1), null);\n            return tAll;\n        }\n    }\n    ;\n    var lft = b2(data, e + 8);\n    if (lft) {\n        var c = lft;\n        var o = b4(data, e + 16);\n        var z = o == 4294967295 || c == 65535;\n        if (z) {\n            var ze = b4(data, e - 12);\n            z = b4(data, ze) == 0x6064B50;\n            if (z) {\n                c = lft = b4(data, ze + 32);\n                o = b4(data, ze + 48);\n            }\n        }\n        var fltr = opts && opts.filter;\n        var _loop_3 = function (i) {\n            var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);\n            o = no;\n            var cbl = function (e, d) {\n                if (e) {\n                    tAll();\n                    cbd(e, null);\n                }\n                else {\n                    if (d)\n                        files[fn] = d;\n                    if (!--lft)\n                        cbd(null, files);\n                }\n            };\n            if (!fltr || fltr({\n                name: fn,\n                size: sc,\n                originalSize: su,\n                compression: c_1\n            })) {\n                if (!c_1)\n                    cbl(null, slc(data, b, b + sc));\n                else if (c_1 == 8) {\n                    var infl = data.subarray(b, b + sc);\n                    // Synchronously decompress under 512KB, or barely-compressed data\n                    if (su < 524288 || sc > 0.8 * su) {\n                        try {\n                            cbl(null, inflateSync(infl, { out: new u8(su) }));\n                        }\n                        catch (e) {\n                            cbl(e, null);\n                        }\n                    }\n                    else\n                        term.push(inflate(infl, { size: su }, cbl));\n                }\n                else\n                    cbl(err(14, 'unknown compression type ' + c_1, 1), null);\n            }\n            else\n                cbl(null, null);\n        };\n        for (var i = 0; i < c; ++i) {\n            _loop_3(i);\n        }\n    }\n    else\n        cbd(null, {});\n    return tAll;\n}\n/**\n * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better\n * performance with more than one file.\n * @param data The raw compressed ZIP file\n * @param opts The ZIP extraction options\n * @returns The decompressed files\n */\nexport function unzipSync(data, opts) {\n    var files = {};\n    var e = data.length - 22;\n    for (; b4(data, e) != 0x6054B50; --e) {\n        if (!e || data.length - e > 65558)\n            err(13);\n    }\n    ;\n    var c = b2(data, e + 8);\n    if (!c)\n        return {};\n    var o = b4(data, e + 16);\n    var z = o == 4294967295 || c == 65535;\n    if (z) {\n        var ze = b4(data, e - 12);\n        z = b4(data, ze) == 0x6064B50;\n        if (z) {\n            c = b4(data, ze + 32);\n            o = b4(data, ze + 48);\n        }\n    }\n    var fltr = opts && opts.filter;\n    for (var i = 0; i < c; ++i) {\n        var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);\n        o = no;\n        if (!fltr || fltr({\n            name: fn,\n            size: sc,\n            originalSize: su,\n            compression: c_2\n        })) {\n            if (!c_2)\n                files[fn] = slc(data, b, b + sc);\n            else if (c_2 == 8)\n                files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });\n            else\n                err(14, 'unknown compression type ' + c_2);\n        }\n    }\n    return files;\n}\n","import type { FeatureCollection, GeoJsonProperties } from 'geojson';\nimport { unzipSync } from 'fflate';\n\nconst ICON_URL = '__geolibre_kml_icon_url';\nconst ICON_SCALE = '__geolibre_kml_icon_scale';\n\ninterface PlacemarkMetadata {\n  name?: string;\n  description?: string;\n  iconHref?: string;\n  iconScale?: number;\n}\n\nfunction children(element: Element, name: string): Element[] {\n  return Array.from(element.children).filter(\n    (child) => child.localName.toLowerCase() === name.toLowerCase(),\n  );\n}\n\nfunction child(element: Element, name: string): Element | undefined {\n  return children(element, name)[0];\n}\n\nfunction childText(element: Element, name: string): string | undefined {\n  const value = child(element, name)?.textContent?.trim();\n  return value || undefined;\n}\n\nfunction archiveEntry(\n  entries: Record<string, Uint8Array>,\n  href: string,\n): [string, Uint8Array] | undefined {\n  const normalize = (value: string) =>\n    value\n      .split(/[?#]/)[0]\n      .replace(/\\\\/g, '/')\n      .replace(/^\\.?\\//, '')\n      .toLowerCase();\n  const target = normalize(href);\n  const exact = Object.entries(entries).find(([name]) => normalize(name) === target);\n  if (exact) return exact;\n  const base = target.split('/').pop();\n  const matches = Object.entries(entries).filter(\n    ([name]) => normalize(name).split('/').pop() === base,\n  );\n  return matches.length === 1 ? matches[0] : undefined;\n}\n\nfunction imageMime(name: string): string | null {\n  const extension = name.split(/[?#]/)[0].split('.').pop()?.toLowerCase();\n  if (extension === 'png') return 'image/png';\n  if (extension === 'jpg' || extension === 'jpeg') return 'image/jpeg';\n  if (extension === 'gif') return 'image/gif';\n  if (extension === 'webp') return 'image/webp';\n  if (extension === 'bmp') return 'image/bmp';\n  return null;\n}\n\nfunction bytesToDataUrl(bytes: Uint8Array, mime: string): Promise<string> {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader();\n    reader.onload = () => resolve(String(reader.result));\n    reader.onerror = () => reject(reader.error ?? new Error('Could not read a KMZ icon.'));\n    reader.readAsDataURL(new Blob([bytes as BlobPart], { type: mime }));\n  });\n}\n\nfunction placemarkMetadata(text: string): PlacemarkMetadata[] {\n  const document = new DOMParser().parseFromString(text, 'application/xml');\n  if (document.querySelector('parsererror')) return [];\n  const styles = new Map<string, { href?: string; scale?: number }>();\n  const elements = Array.from(document.getElementsByTagName('*'));\n  for (const style of elements.filter((element) => element.localName === 'Style')) {\n    const id = style.getAttribute('id');\n    const iconStyle = child(style, 'IconStyle');\n    if (!id || !iconStyle) continue;\n    const icon = child(iconStyle, 'Icon');\n    const href = icon ? childText(icon, 'href') : undefined;\n    const scaleValue = Number(childText(iconStyle, 'scale'));\n    styles.set(id, {\n      href,\n      ...(Number.isFinite(scaleValue) && scaleValue > 0 ? { scale: scaleValue } : {}),\n    });\n  }\n\n  return elements.filter((element) => element.localName === 'Placemark').map((placemark) => {\n    const styleUrl = childText(placemark, 'styleUrl')?.replace(/^#/, '');\n    const style = styleUrl ? styles.get(styleUrl) : undefined;\n    return {\n      name: childText(placemark, 'name'),\n      description: childText(placemark, 'description'),\n      iconHref: style?.href,\n      iconScale: style?.scale,\n    };\n  });\n}\n\nfunction featureName(properties: GeoJsonProperties): string | undefined {\n  const value = properties?.name ?? properties?.Name ?? properties?.NAME;\n  return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Restore KMZ placemark descriptions and embedded icons that GDAL's GeoJSON\n * conversion omits. Features are paired by name and occurrence order.\n */\nexport async function enhanceKmzGeoJSON(\n  source: unknown,\n  collection: FeatureCollection,\n  sourceName?: string,\n): Promise<FeatureCollection> {\n  if (\n    !source ||\n    typeof source !== 'object' ||\n    !('arrayBuffer' in source) ||\n    typeof source.arrayBuffer !== 'function'\n  ) {\n    return collection;\n  }\n  const name =\n    sourceName ?? ('name' in source && typeof source.name === 'string' ? source.name : '');\n  if (name && !name.toLowerCase().endsWith('.kmz')) return collection;\n\n  let entries: Record<string, Uint8Array>;\n  try {\n    entries = unzipSync(new Uint8Array(await source.arrayBuffer()));\n  } catch {\n    return collection;\n  }\n  const kml = Object.entries(entries).find(([entry]) => entry.toLowerCase().endsWith('.kml'));\n  if (!kml) return collection;\n  const metadata = placemarkMetadata(new TextDecoder().decode(kml[1]));\n  if (!metadata.length) return collection;\n\n  const byName = new Map<string, PlacemarkMetadata[]>();\n  for (const item of metadata) {\n    if (!item.name) continue;\n    const queue = byName.get(item.name) ?? [];\n    queue.push(item);\n    byName.set(item.name, queue);\n  }\n\n  const iconUrls = new Map<string, Promise<string | null>>();\n  const resolveIcon = (href: string) => {\n    const cached = iconUrls.get(href);\n    if (cached) return cached;\n    const promise = (async () => {\n      const found = archiveEntry(entries, href);\n      if (!found) return null;\n      const mime = imageMime(found[0]);\n      return mime ? bytesToDataUrl(found[1], mime) : null;\n    })();\n    iconUrls.set(href, promise);\n    return promise;\n  };\n\n  await Promise.all(\n    collection.features.map(async (feature, index) => {\n      const properties = (feature.properties ??= {});\n      const nameValue = featureName(properties);\n      const item = (nameValue ? byName.get(nameValue)?.shift() : undefined) ?? metadata[index];\n      if (!item) return;\n      for (const key of Object.keys(properties)) {\n        const lower = key.toLowerCase();\n        if ((lower === 'name' || lower === 'description') && key !== lower) {\n          delete properties[key];\n        }\n      }\n      if (item.name) properties.name = item.name;\n      if (item.description) properties.description = item.description;\n      if (item.iconScale) properties[ICON_SCALE] = item.iconScale;\n      if (item.iconHref) {\n        const url = await resolveIcon(item.iconHref);\n        if (url) properties[ICON_URL] = url;\n      }\n    }),\n  );\n  return collection;\n}\n\nfunction iconHash(value: string): string {\n  let hash = 2166136261;\n  for (let index = 0; index < value.length; index += 1) {\n    hash = Math.imul(hash ^ value.charCodeAt(index), 16777619);\n  }\n  return (hash >>> 0).toString(16);\n}\n\n/**\n * Register embedded KMZ icons on the map and return a data-driven icon-image\n * expression, or null when the collection has none.\n */\nexport async function prepareKmzIcons(\n  map: {\n    hasImage(id: string): boolean;\n    addImage(id: string, image: HTMLImageElement, options?: { pixelRatio?: number }): void;\n  },\n  collection: FeatureCollection,\n): Promise<unknown[] | null> {\n  const urls = new Set<string>();\n  for (const feature of collection.features) {\n    const value = feature.properties?.[ICON_URL];\n    if (typeof value === 'string') urls.add(value);\n  }\n  if (!urls.size) return null;\n\n  const matches: unknown[] = [];\n  await Promise.all(\n    Array.from(urls).map(\n      (url) =>\n        new Promise<void>((resolve) => {\n          const id = `maplibre-vector-kml-${iconHash(url)}`;\n          matches.push(url, id);\n          if (map.hasImage(id)) {\n            resolve();\n            return;\n          }\n          const image = new Image();\n          image.onload = () => {\n            // ArcGIS KMZ exports bake their KML scale into a 2x raster (the\n            // sample's icons are 60 px for an approximately 30 px symbol).\n            if (!map.hasImage(id)) map.addImage(id, image, { pixelRatio: 2 });\n            resolve();\n          };\n          image.onerror = () => resolve();\n          image.src = url;\n        }),\n    ),\n  );\n  return ['match', ['get', ICON_URL], ...matches, ''];\n}\n","import type { AutoThreshold, RenderMode } from '../core/types';\n\n/**\n * Default thresholds for `'auto'` render mode.\n */\nexport const DEFAULT_AUTO_THRESHOLD: Required<AutoThreshold> = {\n  featureCount: 50_000,\n  byteSize: 25 * 1024 * 1024,\n};\n\n/**\n * Inputs for the render mode decision.\n */\nexport interface RenderModeInputs {\n  /** Mode requested for the layer ('auto' when unspecified) */\n  requested?: RenderMode;\n  /** Control-level default mode */\n  defaultMode?: RenderMode;\n  /** Known feature count */\n  featureCount?: number;\n  /** Known source size in bytes */\n  byteSize?: number;\n  /** Threshold overrides */\n  threshold?: AutoThreshold;\n  /** Whether the tiles pipeline (DuckDB) is usable for this layer */\n  tilesAvailable?: boolean;\n}\n\n/**\n * Resolves the effective render mode for a layer.\n *\n * Explicit per-layer modes win, then the control default, then 'auto'.\n * In auto mode, tiles are chosen when either the feature count or byte\n * size exceeds its threshold (and tiles are available).\n *\n * @param inputs - Decision inputs\n * @returns The resolved render mode ('geojson' or 'tiles')\n */\nexport function decideRenderMode(inputs: RenderModeInputs): 'geojson' | 'tiles' {\n  const {\n    requested,\n    defaultMode,\n    featureCount,\n    byteSize,\n    threshold,\n    tilesAvailable = true,\n  } = inputs;\n\n  const mode = requested && requested !== 'auto' ? requested : (defaultMode ?? 'auto');\n\n  if (mode === 'geojson') return 'geojson';\n  if (mode === 'tiles') return tilesAvailable ? 'tiles' : 'geojson';\n\n  if (!tilesAvailable) return 'geojson';\n\n  const limits = { ...DEFAULT_AUTO_THRESHOLD, ...threshold };\n  const tooManyFeatures = featureCount !== undefined && featureCount > limits.featureCount;\n  const tooLarge = byteSize !== undefined && byteSize > limits.byteSize;\n\n  return tooManyFeatures || tooLarge ? 'tiles' : 'geojson';\n}\n","import type { Map as MapLibreMap, PropertyValueSpecification } from 'maplibre-gl';\nimport type { VectorLayerInfo, VectorLayerStyle } from '../core/types';\n\n/**\n * A paint value: a flat scalar, or a MapLibre data-driven color expression\n * (used for attribute-driven fill/line/circle colors).\n */\nexport type PaintValue =\n  | string\n  | number\n  | PropertyValueSpecification<string>\n  | PropertyValueSpecification<number>;\n\n/**\n * Default style applied to new layers.\n */\nexport const DEFAULT_STYLE: VectorLayerStyle = {\n  fillColor: '#3388ff',\n  fillOpacity: 0.4,\n  lineColor: '#3388ff',\n  lineWidth: 2,\n  circleColor: '#3388ff',\n  circleRadius: 5,\n  circleOpacity: 0.85,\n  pointMode: 'circle',\n  heatmapRadius: 30,\n  heatmapIntensity: 1,\n  clusterRadius: 50,\n  clusterMaxZoom: 14,\n};\n\n// A cold->hot ramp over heatmap-density (0..1) for the heatmap renderer.\nconst HEATMAP_COLOR: PropertyValueSpecification<string> = [\n  'interpolate',\n  ['linear'],\n  ['heatmap-density'],\n  0,\n  'rgba(33,102,172,0)',\n  0.2,\n  'rgb(103,169,207)',\n  0.4,\n  'rgb(209,229,240)',\n  0.6,\n  'rgb(253,219,199)',\n  0.8,\n  'rgb(239,138,98)',\n  1,\n  'rgb(178,24,43)',\n] as unknown as PropertyValueSpecification<string>;\n\n// Cluster bubble radius steps up with the aggregated point count.\nconst CLUSTER_RADIUS: PropertyValueSpecification<number> = [\n  'step',\n  ['get', 'point_count'],\n  16,\n  50,\n  22,\n  200,\n  30,\n] as unknown as PropertyValueSpecification<number>;\n\n/**\n * A single setPaintProperty operation.\n */\nexport interface PaintOp {\n  layerId: string;\n  property: string;\n  value: PaintValue;\n}\n\n/**\n * Suffixes of the map layers created for each vector layer.\n */\nexport const LAYER_SUFFIXES = [\n  'fill',\n  'extrusion',\n  'outline',\n  'line',\n  'circle',\n  'heatmap',\n  'cluster',\n  'cluster-count',\n  'label',\n] as const;\nexport type LayerSuffix = (typeof LAYER_SUFFIXES)[number];\n\n/** Default size, in pixels, of attribute label text. */\nexport const DEFAULT_LABEL_SIZE = 12;\n/** Default color of attribute label text. */\nexport const DEFAULT_LABEL_COLOR = '#333333';\n/** Default color of the halo drawn behind attribute label text. */\nexport const DEFAULT_LABEL_HALO_COLOR = '#ffffff';\n/** Default width, in pixels, of the attribute label text halo. */\nexport const DEFAULT_LABEL_HALO_WIDTH = 1;\n\n/** Resolve a style's point render mode, defaulting to 'circle'. */\nexport function pointModeOf(style: VectorLayerStyle): 'circle' | 'heatmap' | 'cluster' {\n  return style.pointMode ?? 'circle';\n}\n\n/**\n * Whether a style requests attribute labels (a non-empty `labelField`).\n *\n * @param style - The layer style\n * @returns True when a label layer should be created\n */\nexport function hasLabels(style: VectorLayerStyle): boolean {\n  return typeof style.labelField === 'string' && style.labelField.trim().length > 0;\n}\n\n/**\n * Builds the `text-field` expression for a label layer: the feature's\n * `labelField` value coerced to a string, with missing values rendered as\n * empty text (so a cluster aggregate or a feature lacking the field shows\n * nothing rather than breaking the layer).\n *\n * @param style - The layer style (its `labelField` drives the expression)\n * @returns A MapLibre `text-field` expression\n */\nexport function labelTextField(style: VectorLayerStyle): PropertyValueSpecification<string> {\n  return [\n    'to-string',\n    ['coalesce', ['get', style.labelField ?? ''], ''],\n  ] as unknown as PropertyValueSpecification<string>;\n}\n\n/**\n * Builds the symbol-layer layout for a label layer.\n *\n * @param style - The layer style\n * @param visible - Whether the layer starts visible\n * @returns The MapLibre layout object for the label symbol layer\n */\nexport function buildLabelLayout(\n  style: VectorLayerStyle,\n  visible: boolean,\n): Record<string, unknown> {\n  const allowOverlap = style.labelAllowOverlap ?? false;\n  return {\n    visibility: visible ? 'visible' : 'none',\n    'text-field': labelTextField(style),\n    'text-size': style.labelSize ?? DEFAULT_LABEL_SIZE,\n    'symbol-placement': style.labelPlacement === 'line' ? 'line' : 'point',\n    'text-allow-overlap': allowOverlap,\n    'text-ignore-placement': allowOverlap,\n  };\n}\n\n/**\n * Builds the map layer id for a vector layer and suffix.\n *\n * @param layerId - The vector layer id\n * @param suffix - The map layer role\n * @returns The map layer id\n */\nexport function mapLayerId(layerId: string, suffix: LayerSuffix): string {\n  return `${layerId}-${suffix}`;\n}\n\n/**\n * Clamps a master opacity value to the valid [0, 1] range.\n *\n * @param opacity - The requested opacity\n * @returns The clamped opacity (non-finite values become 1)\n */\nexport function clampOpacity(opacity: number): number {\n  if (!Number.isFinite(opacity)) return 1;\n  return Math.min(1, Math.max(0, opacity));\n}\n\n/**\n * Builds the initial paint object for a given map layer role.\n *\n * @param suffix - The map layer role\n * @param style - The layer style\n * @param opacity - Master opacity multiplied into every opacity property\n * @returns The MapLibre paint object\n */\nexport function buildPaint(\n  suffix: LayerSuffix,\n  style: VectorLayerStyle,\n  opacity = 1,\n): Record<string, PaintValue> {\n  const master = clampOpacity(opacity);\n  // A data-driven color expression, when present, overrides the flat color so\n  // attribute-driven (categorized/graduated) styling renders.\n  const fillColor = style.fillColorExpression ?? style.fillColor;\n  const lineColor = style.lineColorExpression ?? style.lineColor;\n  const circleColor = style.circleColorExpression ?? style.circleColor;\n  switch (suffix) {\n    case 'fill':\n      return {\n        'fill-color': fillColor,\n        'fill-opacity': style.fillOpacity * master,\n      };\n    case 'extrusion':\n      return {\n        // Data-driven extrusion color wins over the flat one; both fall back to\n        // the fill color so an extruded layer is never left uncolored.\n        'fill-extrusion-color':\n          style.extrusionColorExpression ?? style.extrusionColor ?? fillColor,\n        'fill-extrusion-opacity': (style.extrusionOpacity ?? 1) * master,\n        // A constant or a data-driven expression (e.g. ['get', 'height']);\n        // unset means 0, which renders flat until a height is provided.\n        'fill-extrusion-height': style.extrusionHeight ?? 0,\n        'fill-extrusion-base': style.extrusionBase ?? 0,\n      };\n    case 'outline':\n      return {\n        'line-color': lineColor,\n        'line-width': style.lineWidth,\n        'line-opacity': master,\n      };\n    case 'line':\n      return {\n        'line-color': lineColor,\n        'line-width': style.lineWidth,\n        'line-opacity': master,\n      };\n    case 'circle':\n      return {\n        'circle-color': circleColor,\n        'circle-radius': style.circleRadius,\n        'circle-opacity': style.circleOpacity * master,\n        'circle-stroke-color': '#ffffff',\n        'circle-stroke-width': 1,\n        'circle-stroke-opacity': master,\n      };\n    case 'heatmap':\n      return {\n        'heatmap-radius': style.heatmapRadius ?? 30,\n        'heatmap-intensity': style.heatmapIntensity ?? 1,\n        'heatmap-opacity': master,\n        'heatmap-color': HEATMAP_COLOR,\n      };\n    case 'cluster':\n      return {\n        // Use the resolved circleColor (data-driven expression or flat) so an\n        // initial cluster render honors the same color contract as a later patch.\n        'circle-color': circleColor,\n        'circle-radius': CLUSTER_RADIUS,\n        'circle-opacity': style.circleOpacity * master,\n        'circle-stroke-color': '#ffffff',\n        'circle-stroke-width': 1,\n        'circle-stroke-opacity': master,\n      };\n    case 'cluster-count':\n      return {\n        'text-color': '#ffffff',\n        'text-opacity': master,\n      };\n    case 'label':\n      return {\n        'text-color': style.labelColor ?? DEFAULT_LABEL_COLOR,\n        'text-halo-color': style.labelHaloColor ?? DEFAULT_LABEL_HALO_COLOR,\n        'text-halo-width': Math.max(0, style.labelHaloWidth ?? DEFAULT_LABEL_HALO_WIDTH),\n        'text-opacity': master,\n      };\n  }\n}\n\n/**\n * Maps a style patch to the setPaintProperty operations it implies.\n *\n * Only operations for map layers that exist on the vector layer are\n * returned. Style opacities are multiplied by the layer's master\n * opacity so a patch cannot undo a host-applied opacity.\n *\n * @param info - The vector layer\n * @param patch - Partial style update\n * @param opacity - Master opacity multiplied into opacity properties\n * @returns The list of paint operations to apply\n */\nexport function stylePatchToPaintOps(\n  info: Pick<VectorLayerInfo, 'id' | 'layerIds'>,\n  patch: Partial<VectorLayerStyle>,\n  opacity = 1,\n): PaintOp[] {\n  const master = clampOpacity(opacity);\n  const ops: PaintOp[] = [];\n  const has = (suffix: LayerSuffix) => info.layerIds.includes(mapLayerId(info.id, suffix));\n  const push = (suffix: LayerSuffix, property: string, value: PaintValue | undefined) => {\n    if (value !== undefined && has(suffix)) {\n      ops.push({ layerId: mapLayerId(info.id, suffix), property, value });\n    }\n  };\n\n  // A data-driven color expression in the patch overrides the flat color.\n  const fillColor = patch.fillColorExpression ?? patch.fillColor;\n  const lineColor = patch.lineColorExpression ?? patch.lineColor;\n  const circleColor = patch.circleColorExpression ?? patch.circleColor;\n\n  push('fill', 'fill-color', fillColor);\n  push('fill', 'fill-opacity', patch.fillOpacity === undefined ? undefined : patch.fillOpacity * master);\n  // Extrusion paint. Toggling extrusionEnabled itself is structural (handled by\n  // the layer manager, which rebuilds the polygon layers); these ops cover\n  // restyle edits while extrusion stays on, applied only when the layer has the\n  // 'extrusion' map layer.\n  push('extrusion', 'fill-extrusion-color', patch.extrusionColorExpression ?? patch.extrusionColor);\n  push(\n    'extrusion',\n    'fill-extrusion-opacity',\n    patch.extrusionOpacity === undefined ? undefined : patch.extrusionOpacity * master,\n  );\n  push('extrusion', 'fill-extrusion-height', patch.extrusionHeight);\n  push('extrusion', 'fill-extrusion-base', patch.extrusionBase);\n  push('outline', 'line-color', lineColor);\n  push('outline', 'line-width', patch.lineWidth);\n  push('line', 'line-color', lineColor);\n  push('line', 'line-width', patch.lineWidth);\n  push('circle', 'circle-color', circleColor);\n  push('circle', 'circle-radius', patch.circleRadius);\n  push('circle', 'circle-opacity', patch.circleOpacity === undefined ? undefined : patch.circleOpacity * master);\n  // Heatmap radius/intensity are plain paint updates (no rebuild needed); the\n  // cluster bubble tracks the circle color and opacity. pointMode and cluster\n  // radius/maxZoom changes are structural and handled by the layer manager.\n  push('heatmap', 'heatmap-radius', patch.heatmapRadius);\n  push('heatmap', 'heatmap-intensity', patch.heatmapIntensity);\n  push('cluster', 'circle-color', circleColor);\n  push('cluster', 'circle-opacity', patch.circleOpacity === undefined ? undefined : patch.circleOpacity * master);\n  // Label paint. text-size, placement, and the text-field itself are layout\n  // (not paint) and are applied by the layer manager, which also adds or\n  // removes the label layer when the labelField is set or cleared.\n  push('label', 'text-color', patch.labelColor);\n  push('label', 'text-halo-color', patch.labelHaloColor);\n  push(\n    'label',\n    'text-halo-width',\n    patch.labelHaloWidth === undefined ? undefined : Math.max(0, patch.labelHaloWidth),\n  );\n\n  return ops;\n}\n\n/**\n * Maps a master opacity change to the setPaintProperty operations it\n * implies, multiplying the style's own opacities where applicable.\n *\n * @param info - The vector layer\n * @param style - The layer's current style\n * @param opacity - The new master opacity (0-1)\n * @returns The list of paint operations to apply\n */\nexport function opacityToPaintOps(\n  info: Pick<VectorLayerInfo, 'id' | 'layerIds'>,\n  style: VectorLayerStyle,\n  opacity: number,\n): PaintOp[] {\n  const master = clampOpacity(opacity);\n  const ops: PaintOp[] = [];\n  const has = (suffix: LayerSuffix) => info.layerIds.includes(mapLayerId(info.id, suffix));\n  const push = (suffix: LayerSuffix, property: string, value: string | number) => {\n    if (has(suffix)) {\n      ops.push({ layerId: mapLayerId(info.id, suffix), property, value });\n    }\n  };\n\n  push('fill', 'fill-opacity', style.fillOpacity * master);\n  push('extrusion', 'fill-extrusion-opacity', (style.extrusionOpacity ?? 1) * master);\n  push('outline', 'line-opacity', master);\n  push('line', 'line-opacity', master);\n  push('circle', 'circle-opacity', style.circleOpacity * master);\n  push('circle', 'circle-stroke-opacity', master);\n  push('heatmap', 'heatmap-opacity', master);\n  push('cluster', 'circle-opacity', style.circleOpacity * master);\n  push('cluster', 'circle-stroke-opacity', master);\n  push('cluster-count', 'text-opacity', master);\n  push('label', 'text-opacity', master);\n\n  return ops;\n}\n\n/**\n * Applies a style patch to the map layers of a vector layer.\n *\n * @param map - The MapLibre map\n * @param info - The vector layer\n * @param patch - Partial style update\n * @param opacity - Master opacity multiplied into opacity properties\n */\nexport function applyStyle(\n  map: MapLibreMap,\n  info: Pick<VectorLayerInfo, 'id' | 'layerIds'>,\n  patch: Partial<VectorLayerStyle>,\n  opacity = 1,\n): void {\n  for (const op of stylePatchToPaintOps(info, patch, opacity)) {\n    map.setPaintProperty(op.layerId, op.property, op.value);\n  }\n}\n\n/**\n * Applies a master opacity change to the map layers of a vector layer.\n *\n * @param map - The MapLibre map\n * @param info - The vector layer\n * @param style - The layer's current style\n * @param opacity - The new master opacity (0-1)\n */\nexport function applyOpacity(\n  map: MapLibreMap,\n  info: Pick<VectorLayerInfo, 'id' | 'layerIds'>,\n  style: VectorLayerStyle,\n  opacity: number,\n): void {\n  for (const op of opacityToPaintOps(info, style, opacity)) {\n    map.setPaintProperty(op.layerId, op.property, op.value);\n  }\n}\n","import type {\n  FilterSpecification,\n  Map as MapLibreMap,\n  SourceSpecification,\n} from 'maplibre-gl';\nimport type { FeatureCollection } from 'geojson';\nimport type { GeometryCategory, VectorLayerStyle } from '../core/types';\nimport type { Bbox } from '../utils/geometry';\nimport { buildLabelLayout, buildPaint, hasLabels, mapLayerId, pointModeOf } from './styleBuilder';\n\n/** Map layer roles created by the geometry-type loop (excludes heatmap/cluster). */\ntype GeometrySuffix = 'fill' | 'extrusion' | 'outline' | 'line' | 'circle';\n\n/**\n * Builds the map source id for a vector layer.\n *\n * @param layerId - The vector layer id\n * @returns The map source id\n */\nexport function sourceIdFor(layerId: string): string {\n  return `${layerId}-source`;\n}\n\n/**\n * Returns the map layer roles needed for a geometry category.\n *\n * Mixed or unknown geometry gets all roles with geometry-type filters so\n * each feature renders with the appropriate layer.\n *\n * When `extrude` is set, polygon features render as a single `fill-extrusion`\n * layer (the flat `fill`/`outline` pair is replaced); other geometries are\n * unaffected.\n *\n * @param category - The geometry category\n * @param extrude - Render polygons as 3D extrusions instead of a flat fill\n * @returns The layer suffixes to create\n */\nexport function suffixesForGeometry(\n  category: GeometryCategory,\n  extrude = false,\n): GeometrySuffix[] {\n  switch (category) {\n    case 'polygon':\n      return extrude ? ['extrusion'] : ['fill', 'outline'];\n    case 'line':\n      return ['line'];\n    case 'point':\n      return ['circle'];\n    default:\n      return extrude ? ['extrusion', 'line', 'circle'] : ['fill', 'outline', 'line', 'circle'];\n  }\n}\n\nconst SUFFIX_TYPES: Record<GeometrySuffix, 'fill' | 'fill-extrusion' | 'line' | 'circle'> = {\n  fill: 'fill',\n  extrusion: 'fill-extrusion',\n  outline: 'line',\n  line: 'line',\n  circle: 'circle',\n};\n\nconst SUFFIX_FILTERS: Record<GeometrySuffix, FilterSpecification> = {\n  fill: ['==', ['geometry-type'], 'Polygon'],\n  extrusion: ['==', ['geometry-type'], 'Polygon'],\n  outline: ['==', ['geometry-type'], 'Polygon'],\n  line: ['==', ['geometry-type'], 'LineString'],\n  circle: ['==', ['geometry-type'], 'Point'],\n};\n\nconst POINT_FILTER: FilterSpecification = ['==', ['geometry-type'], 'Point'];\nconst CLUSTER_FILTER: FilterSpecification = ['has', 'point_count'];\nconst UNCLUSTERED_FILTER: FilterSpecification = ['!', ['has', 'point_count']];\n\n/**\n * Options for adding the map layers of a vector layer.\n */\nexport interface AddLayersOptions {\n  /** The vector layer id */\n  layerId: string;\n  /** Geometry category determining which map layers are created */\n  geometryType: GeometryCategory;\n  /** Layer style */\n  style: VectorLayerStyle;\n  /** Whether the layer starts visible */\n  visible: boolean;\n  /** Master opacity (0-1) multiplied into every style opacity */\n  opacity?: number;\n  /** source-layer name for vector tile sources (omit for geojson) */\n  sourceLayer?: string;\n  /** Existing map layer id to insert the new layers before */\n  beforeId?: string;\n  /** Per-feature KMZ icon-image expression for point layers. */\n  kmlIconImage?: unknown[] | null;\n}\n\n/**\n * Adds a GeoJSON source to the map.\n *\n * @param map - The MapLibre map\n * @param layerId - The vector layer id\n * @param data - The FeatureCollection to render\n * @param attribution - Optional attribution string\n * @returns The created source id\n */\nexport function addGeoJSONSource(\n  map: MapLibreMap,\n  layerId: string,\n  data: FeatureCollection,\n  attribution?: string,\n  cluster?: { radius: number; maxZoom: number },\n): string {\n  const sourceId = sourceIdFor(layerId);\n  const spec: SourceSpecification = { type: 'geojson', data };\n  if (attribution) spec.attribution = attribution;\n  if (cluster) {\n    spec.cluster = true;\n    spec.clusterRadius = cluster.radius;\n    spec.clusterMaxZoom = cluster.maxZoom;\n  }\n  map.addSource(sourceId, spec);\n  return sourceId;\n}\n\n/**\n * Cluster options for a GeoJSON source when a point layer's style requests\n * clustering, or undefined otherwise (the source stays unclustered). Only\n * applies to geojson-rendered point layers.\n *\n * @param geometryType - The layer's geometry category\n * @param style - The layer style\n * @param sourceLayer - Set for vector-tile sources (clustering is geojson-only)\n * @returns Cluster options, or undefined\n */\nexport function clusterOptionsFor(\n  geometryType: GeometryCategory,\n  style: VectorLayerStyle,\n  sourceLayer?: string,\n): { radius: number; maxZoom: number } | undefined {\n  if (sourceLayer || geometryType !== 'point') return undefined;\n  if (pointModeOf(style) !== 'cluster') return undefined;\n  return { radius: style.clusterRadius ?? 50, maxZoom: style.clusterMaxZoom ?? 14 };\n}\n\n/**\n * Options for adding a dynamic vector tile source.\n */\nexport interface AddVectorSourceOptions {\n  /** Tile URL template (e.g. duckdb://layer/{z}/{x}/{y}) */\n  tileUrl: string;\n  /** Maximum zoom at which tiles are generated */\n  maxzoom: number;\n  /** Layer extent used to skip out-of-bounds tile requests */\n  bounds?: Bbox;\n  /** Optional attribution string */\n  attribution?: string;\n}\n\n/**\n * Adds a vector tile source backed by the duckdb:// protocol.\n *\n * @param map - The MapLibre map\n * @param layerId - The vector layer id\n * @param options - Source options\n * @returns The created source id\n */\nexport function addVectorTileSource(\n  map: MapLibreMap,\n  layerId: string,\n  options: AddVectorSourceOptions,\n): string {\n  const sourceId = sourceIdFor(layerId);\n  const spec: SourceSpecification = {\n    type: 'vector',\n    tiles: [options.tileUrl],\n    minzoom: 0,\n    maxzoom: options.maxzoom,\n  };\n  if (options.bounds) spec.bounds = options.bounds;\n  if (options.attribution) spec.attribution = options.attribution;\n  map.addSource(sourceId, spec);\n  return sourceId;\n}\n\n/**\n * Adds the styled map layers for a vector layer source.\n *\n * @param map - The MapLibre map\n * @param options - Layer creation options\n * @returns The created map layer ids\n */\nexport function addGeometryLayers(map: MapLibreMap, options: AddLayersOptions): string[] {\n  const { layerId, geometryType, style, visible, opacity, sourceLayer, beforeId, kmlIconImage } =\n    options;\n  const sourceId = sourceIdFor(layerId);\n  const layout = { visibility: visible ? 'visible' : 'none' };\n\n  // Only honor beforeId when the target layer exists; addLayer throws\n  // otherwise (e.g. a label layer absent from the active style).\n  const before = beforeId && map.getLayer(beforeId) ? beforeId : undefined;\n\n  const add = (id: string, spec: Record<string, unknown>): string => {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    map.addLayer({ id, source: sourceId, layout, ...spec } as any, before);\n    return id;\n  };\n\n  // Geojson point layers honor the style's pointMode (heatmap/cluster). Tiles\n  // (sourceLayer set) and other geometries always use the standard roles.\n  const pointMode = !sourceLayer && geometryType === 'point' ? pointModeOf(style) : 'circle';\n\n  // An attribute label layer is appended last so it draws on top of the\n  // geometry. Added for every geometry type and render mode; the symbol layer\n  // references the same source (and source-layer for tiles).\n  const withLabel = (ids: string[]): string[] => {\n    if (hasLabels(style)) {\n      ids.push(addLabelLayer(map, { layerId, style, visible, opacity, sourceLayer, beforeId }));\n    }\n    return ids;\n  };\n\n  if (pointMode === 'heatmap') {\n    return withLabel([\n      add(mapLayerId(layerId, 'heatmap'), {\n        type: 'heatmap',\n        filter: POINT_FILTER,\n        paint: buildPaint('heatmap', style, opacity),\n      }),\n    ]);\n  }\n\n  if (pointMode === 'cluster') {\n    return withLabel([\n      add(mapLayerId(layerId, 'cluster'), {\n        type: 'circle',\n        filter: CLUSTER_FILTER,\n        paint: buildPaint('cluster', style, opacity),\n      }),\n      add(mapLayerId(layerId, 'cluster-count'), {\n        type: 'symbol',\n        filter: CLUSTER_FILTER,\n        layout: {\n          ...layout,\n          'text-field': ['get', 'point_count_abbreviated'],\n          'text-size': 12,\n          'text-allow-overlap': true,\n          'text-ignore-placement': true,\n        },\n        paint: buildPaint('cluster-count', style, opacity),\n      }),\n      add(mapLayerId(layerId, 'circle'), {\n        type: 'circle',\n        filter: UNCLUSTERED_FILTER,\n        paint: buildPaint('circle', style, opacity),\n      }),\n    ]);\n  }\n\n  const ids = suffixesForGeometry(geometryType, style.extrusionEnabled === true).map((suffix) =>\n      add(mapLayerId(layerId, suffix), {\n        type: SUFFIX_TYPES[suffix],\n        ...(sourceLayer ? { 'source-layer': sourceLayer } : {}),\n        filter:\n          suffix === 'circle' && kmlIconImage\n            ? ['all', SUFFIX_FILTERS.circle, ['!', ['has', '__geolibre_kml_icon_url']]]\n            : SUFFIX_FILTERS[suffix],\n        paint: buildPaint(suffix, style, opacity),\n      }),\n    );\n  if (geometryType === 'point' && kmlIconImage) {\n    ids.push(\n      add(`${layerId}-kml-icon`, {\n        type: 'symbol',\n        filter: ['all', POINT_FILTER, ['has', '__geolibre_kml_icon_url']],\n        layout: {\n          ...layout,\n          'icon-image': kmlIconImage,\n          'icon-size': 1,\n          'icon-allow-overlap': true,\n          'icon-ignore-placement': true,\n        },\n        paint: { 'icon-opacity': opacity },\n      }),\n    );\n  }\n  return withLabel(ids);\n}\n\n/**\n * Options for adding the attribute label layer of a vector layer.\n */\nexport interface AddLabelLayerOptions {\n  /** The vector layer id */\n  layerId: string;\n  /** Layer style (its label* fields drive the symbol layer) */\n  style: VectorLayerStyle;\n  /** Whether the layer starts visible */\n  visible: boolean;\n  /** Master opacity (0-1) multiplied into the text opacity */\n  opacity?: number;\n  /** source-layer name for vector tile sources (omit for geojson) */\n  sourceLayer?: string;\n  /** Existing map layer id to insert the label layer before */\n  beforeId?: string;\n}\n\n/**\n * Adds the attribute label `symbol` layer for a vector layer, rendering the\n * style's `labelField` value as text for every feature.\n *\n * @param map - The MapLibre map\n * @param options - Label layer creation options\n * @returns The created label map layer id\n */\nexport function addLabelLayer(map: MapLibreMap, options: AddLabelLayerOptions): string {\n  const { layerId, style, visible, opacity, sourceLayer, beforeId } = options;\n  const id = mapLayerId(layerId, 'label');\n  const before = beforeId && map.getLayer(beforeId) ? beforeId : undefined;\n  map.addLayer(\n    {\n      id,\n      type: 'symbol',\n      source: sourceIdFor(layerId),\n      ...(sourceLayer ? { 'source-layer': sourceLayer } : {}),\n      layout: buildLabelLayout(style, visible),\n      paint: buildPaint('label', style, opacity),\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    } as any,\n    before,\n  );\n  return id;\n}\n\n/**\n * Sets the visibility of all map layers of a vector layer.\n *\n * @param map - The MapLibre map\n * @param layerIds - The map layer ids\n * @param visible - Whether the layers should be visible\n */\nexport function setLayersVisibility(\n  map: MapLibreMap,\n  layerIds: string[],\n  visible: boolean,\n): void {\n  for (const id of layerIds) {\n    // A structural point-renderer rebuild removes the previous native layers\n    // before its async icon preparation completes. Visibility can be\n    // reconciled during that handoff, so ignore ids that have already gone.\n    if (map.getLayer(id)) {\n      map.setLayoutProperty(id, 'visibility', visible ? 'visible' : 'none');\n    }\n  }\n}\n\n/**\n * Removes the map layers and source of a vector layer.\n *\n * @param map - The MapLibre map\n * @param layerIds - The map layer ids to remove\n * @param sourceId - The source id to remove\n */\nexport function removeLayersAndSource(\n  map: MapLibreMap,\n  layerIds: string[],\n  sourceId: string,\n): void {\n  for (const id of layerIds) {\n    if (map.getLayer(id)) map.removeLayer(id);\n  }\n  if (map.getSource(sourceId)) map.removeSource(sourceId);\n}\n","/**\n * Lazy access to the maplibre-gl module without a static value import.\n *\n * The global `maplibregl` (UMD build or host app) is preferred so\n * module-level registries like addProtocol land on the SAME module\n * instance that owns the map; a bundled second copy of maplibre-gl\n * would register them where the host map never looks. Falls back to\n * importing the peer dependency.\n */\n\nimport type { LngLat, Map as MapLibreMap } from 'maplibre-gl';\n\n/**\n * The subset of the maplibre-gl module surface this library uses.\n */\nexport interface MaplibreModule {\n  addProtocol(\n    name: string,\n    loadFn: (\n      params: { url: string },\n      abortController: AbortController,\n    ) => Promise<{ data: Uint8Array }>,\n  ): void;\n  removeProtocol(name: string): void;\n  Popup: new (options?: {\n    closeButton?: boolean;\n    maxWidth?: string;\n    className?: string;\n  }) => {\n    setLngLat(lngLat: LngLat | [number, number]): unknown;\n    setDOMContent(node: Node): unknown;\n    addTo(map: MapLibreMap): unknown;\n    remove(): void;\n  };\n}\n\nlet modulePromise: Promise<MaplibreModule> | undefined;\n\n/**\n * Resolves the maplibre-gl module, preferring the global instance.\n *\n * @returns The maplibre-gl module\n */\nexport function getMaplibre(): Promise<MaplibreModule> {\n  if (!modulePromise) {\n    const globalMaplibre = (globalThis as Record<string, unknown>).maplibregl as\n      | MaplibreModule\n      | undefined;\n    if (globalMaplibre && typeof globalMaplibre.addProtocol === 'function') {\n      modulePromise = Promise.resolve(globalMaplibre);\n    } else {\n      modulePromise = import('maplibre-gl').then(\n        (module) => (module.default ?? module) as unknown as MaplibreModule,\n      );\n    }\n    modulePromise.catch(() => {\n      modulePromise = undefined;\n    });\n  }\n  return modulePromise;\n}\n","import { getMaplibre } from '../utils/maplibre';\n\n/**\n * Custom protocol scheme used for dynamic DuckDB tiles.\n */\nexport const TILE_PROTOCOL = 'duckdb';\n\n/**\n * Produces an MVT tile for a z/x/y request.\n */\nexport type TileProvider = (\n  z: number,\n  x: number,\n  y: number,\n  signal: AbortSignal,\n) => Promise<Uint8Array>;\n\nconst providers = new Map<string, TileProvider>();\nlet protocolRegistered = false;\n\n/**\n * Builds the tile URL template for a registered tile provider.\n *\n * The key is URI-encoded so it round-trips through parseTileUrl even\n * when it contains reserved characters.\n *\n * @param providerKey - The provider registry key\n * @returns The duckdb:// tile URL template\n */\nexport function tileUrlFor(providerKey: string): string {\n  return `${TILE_PROTOCOL}://${encodeURIComponent(providerKey)}/{z}/{x}/{y}`;\n}\n\n/**\n * Parsed components of a duckdb:// tile URL.\n */\nexport interface ParsedTileUrl {\n  providerKey: string;\n  z: number;\n  x: number;\n  y: number;\n}\n\n/**\n * Parses a duckdb:// tile URL into its components.\n *\n * @param url - The request URL\n * @returns The parsed components, or null when the URL is not a tile URL\n */\nexport function parseTileUrl(url: string): ParsedTileUrl | null {\n  const match = new RegExp(`^${TILE_PROTOCOL}://([^/]+)/(\\\\d+)/(\\\\d+)/(\\\\d+)(?:\\\\.pbf)?$`).exec(\n    url,\n  );\n  if (!match) return null;\n  return {\n    providerKey: decodeURIComponent(match[1]),\n    z: Number(match[2]),\n    x: Number(match[3]),\n    y: Number(match[4]),\n  };\n}\n\n/**\n * Handles a tile request for the duckdb:// protocol.\n *\n * Unknown layers resolve to an empty tile so requests in flight during\n * layer removal do not surface errors.\n *\n * @param url - The request URL\n * @param signal - Abort signal from MapLibre\n * @returns The tile bytes\n */\nexport async function loadTile(url: string, signal: AbortSignal): Promise<Uint8Array> {\n  const parsed = parseTileUrl(url);\n  if (!parsed) {\n    throw new Error(`Invalid ${TILE_PROTOCOL}:// tile URL: ${url}`);\n  }\n\n  const provider = providers.get(parsed.providerKey);\n  if (!provider) return new Uint8Array(0);\n\n  return provider(parsed.z, parsed.x, parsed.y, signal);\n}\n\n/**\n * Registers a tile provider, installing the duckdb:// protocol handler\n * on first use.\n *\n * The registry is process-wide, so callers must pass a globally unique\n * key (not the public layer id, which can repeat across controls).\n *\n * Resolves once the protocol handler is installed, so a tile source\n * added afterwards is guaranteed to find it.\n *\n * @param providerKey - Globally unique provider registry key\n * @param provider - The tile provider\n */\nexport async function registerTileProvider(\n  providerKey: string,\n  provider: TileProvider,\n): Promise<void> {\n  providers.set(providerKey, provider);\n  if (!protocolRegistered) {\n    const api = await getMaplibre();\n    if (!protocolRegistered) {\n      api.addProtocol(TILE_PROTOCOL, async (params, abortController) => {\n        const data = await loadTile(params.url, abortController.signal);\n        return { data };\n      });\n      protocolRegistered = true;\n    }\n  }\n}\n\n/**\n * Removes a tile provider, uninstalling the protocol handler when no\n * providers remain.\n *\n * @param providerKey - The provider registry key\n */\nexport function unregisterTileProvider(providerKey: string): void {\n  providers.delete(providerKey);\n  if (providers.size === 0 && protocolRegistered) {\n    void getMaplibre()\n      .then((api) => {\n        // Re-check: a provider may have been registered meanwhile.\n        if (providers.size === 0 && protocolRegistered) {\n          api.removeProtocol(TILE_PROTOCOL);\n          protocolRegistered = false;\n        }\n      })\n      .catch(() => {\n        // Leave state unchanged; a later unregister can retry teardown.\n      });\n  }\n}\n\n/**\n * Returns whether a tile provider is registered for a key.\n *\n * @param providerKey - The provider registry key\n * @returns True when a provider is registered\n */\nexport function hasTileProvider(providerKey: string): boolean {\n  return providers.has(providerKey);\n}\n","import type { Map as MapLibreMap } from 'maplibre-gl';\nimport type { Bbox } from './geometry';\n\n/**\n * Globe-safe camera fitting.\n *\n * A globe can only ever show half the planet's longitudes at once, so an extent\n * wider than a hemisphere has no camera that contains it. MapLibre's\n * `fitBounds` does not treat that as the special case it is: past roughly a\n * hemisphere its globe camera solver stops pulling back and starts zooming *in*\n * again. Measured against a live map on a 576x648 viewport with 40px padding,\n * sampling the box outline to see how much of it lands inside the padded\n * viewport:\n *\n * | bbox width | globe zoom | outline in frame | flat-map zoom |\n * | ---------- | ---------- | ---------------- | ------------- |\n * | 90 deg     | 2.27       | 42/42            | 1.95          |\n * | 150 deg    | 1.97       | 42/42            | 1.22          |\n * | 170 deg    | 2.00       | 42/42            | 1.07          |\n * | 175 deg    | 2.01       | 34/42            | 1.03          |\n * | 259 deg    | 3.10       | 10/42            | 0.43          |\n * | 360 deg    | 2.36       | 46/84            | 0.00          |\n *\n * So MapLibre frames narrow and continent-scale extents correctly and only\n * breaks down past a hemisphere, where it leaves the data behind the horizon\n * and the layer reads as \"added, but nothing on the map\". It takes very little\n * to get there: a mostly-US point layer with three records in Europe and Asia\n * already spans 259 degrees.\n *\n * {@link fitMapToBbox} therefore caps the zoom at the flat Web Mercator fit for\n * exactly those extents, so the camera settles on a whole-globe view instead.\n * Fits MapLibre already handles are passed through untouched. The cap is a\n * ceiling and never a floor, so it cannot tighten a fit; and under the mercator\n * projection it equals what `fitBounds` computes anyway, making it a no-op\n * there.\n */\n\n/**\n * The latitude at which Web Mercator is truncated; the projection runs to\n * infinity at the poles.\n */\nconst MAX_MERCATOR_LATITUDE = 85.051129;\n\n/** The tile size MapLibre's zoom scale is defined against. */\nconst TILE_SIZE = 512;\n\n/**\n * The widest longitude span a globe can show at once: half the planet. Past\n * this, no camera contains the extent and MapLibre's globe fit degrades (see\n * the measurements above), so the flat-map ceiling takes over. The measured\n * boundary sits a little under this (containment ends around 175 degrees on a\n * 576x648 viewport, since the padding eats into the visible hemisphere), but\n * the geometric limit is used rather than a viewport-tuned constant: extents in\n * that narrow band keep MapLibre's own fit, which puts only their extreme\n * east/west edges just outside the padding.\n */\nconst GLOBE_VISIBLE_LONGITUDE_SPAN = 180;\n\n/** Normalized (0..1) Web Mercator northing for a latitude in degrees. */\nfunction mercatorY(latitude: number): number {\n  const clamped = Math.min(MAX_MERCATOR_LATITUDE, Math.max(-MAX_MERCATOR_LATITUDE, latitude));\n  return 0.5 - Math.log(Math.tan(Math.PI / 4 + (clamped * Math.PI) / 360)) / (2 * Math.PI);\n}\n\n/**\n * The longitude span of a bbox in degrees, taking the short way round so an\n * extent crossing the antimeridian (`west` greater than `east`, e.g.\n * `[170, …, -170, …]`) reads as the ~20 degrees it covers rather than the ~340\n * degree complement. A full-world box (`[-180, …, 180, …]`) still reads as 360.\n *\n * @param west - The bbox's western edge in degrees\n * @param east - The bbox's eastern edge in degrees\n * @returns The span in degrees, in [0, 360]\n */\nexport function longitudeSpan(west: number, east: number): number {\n  const span = east - west;\n  if (span >= 360) return 360;\n  return ((span % 360) + 360) % 360;\n}\n\n/**\n * Computes the zoom at which a bbox fits a viewport under flat Web Mercator.\n *\n * @param bbox - The extent to fit, as [west, south, east, north] in EPSG:4326.\n *   A `west` greater than `east` is read as crossing the antimeridian.\n * @param viewport - The map viewport size in CSS pixels\n * @param padding - Padding to keep free on every side, in CSS pixels\n * @returns The fitting zoom, or undefined when the inputs cannot produce one\n *   (an unmeasurable viewport, or an extent with no width and no height)\n */\nexport function mercatorFitZoom(\n  bbox: Bbox,\n  viewport: { width: number; height: number },\n  padding: number,\n): number | undefined {\n  if (!bbox.every((value) => Number.isFinite(value))) return undefined;\n  const [west, south, east, north] = bbox;\n  const usableWidth = viewport.width - 2 * padding;\n  const usableHeight = viewport.height - 2 * padding;\n  if (!(usableWidth > 0) || !(usableHeight > 0)) return undefined;\n\n  // Either span may be zero (a point layer, or a horizontal line); such an\n  // axis simply places no constraint on the zoom.\n  const worldFractionX = longitudeSpan(west, east) / 360;\n  const worldFractionY = Math.abs(mercatorY(south) - mercatorY(north));\n\n  const scales: number[] = [];\n  if (worldFractionX > 0) scales.push(usableWidth / (TILE_SIZE * worldFractionX));\n  if (worldFractionY > 0) scales.push(usableHeight / (TILE_SIZE * worldFractionY));\n  if (scales.length === 0) return undefined;\n\n  const zoom = Math.log2(Math.min(...scales));\n  return Number.isFinite(zoom) ? zoom : undefined;\n}\n\n/** The camera options {@link fitMapToBbox} forwards to `map.fitBounds`. */\nexport interface FitBboxOptions {\n  /** Padding to keep free on every side, in CSS pixels. */\n  padding: number;\n  /** Animation length in milliseconds. */\n  duration?: number;\n  /** The closest zoom the fit may settle on, before the flat-map ceiling. */\n  maxZoom?: number;\n}\n\n/**\n * Reads the map's viewport in CSS pixels, when it can be measured. A canvas\n * that has never been laid out (jsdom, a detached container) reports zero and\n * yields undefined, so the caller skips the ceiling rather than computing one\n * from a bogus size.\n */\nfunction viewportOf(map: MapLibreMap): { width: number; height: number } | undefined {\n  const canvas = typeof map.getCanvas === 'function' ? map.getCanvas() : undefined;\n  const width = canvas?.clientWidth ?? 0;\n  const height = canvas?.clientHeight ?? 0;\n  return width > 0 && height > 0 ? { width, height } : undefined;\n}\n\n/**\n * The zoom ceiling to send with a fit: the caller's own, tightened to the\n * flat-map fit for an extent too wide for any globe camera to contain.\n */\nfunction ceilingFor(\n  map: MapLibreMap,\n  bbox: Bbox,\n  options: FitBboxOptions,\n): number | undefined {\n  const [west, , east] = bbox;\n  const fitsOnAGlobe =\n    !Number.isFinite(west) ||\n    !Number.isFinite(east) ||\n    longitudeSpan(west, east) <= GLOBE_VISIBLE_LONGITUDE_SPAN;\n  if (fitsOnAGlobe) return options.maxZoom;\n\n  const viewport = viewportOf(map);\n  const flatZoom = viewport ? mercatorFitZoom(bbox, viewport, options.padding) : undefined;\n  if (flatZoom === undefined) return options.maxZoom;\n  return Math.min(flatZoom, options.maxZoom ?? Number.POSITIVE_INFINITY);\n}\n\n/**\n * Fits the map to a bbox, capping the zoom at the flat-map fit when the extent\n * is wider than a globe can show, so it cannot be framed on empty space.\n *\n * @param map - The map to move\n * @param bbox - The extent to fit, as [west, south, east, north] in EPSG:4326\n * @param options - Padding, animation length, and an optional zoom ceiling\n */\nexport function fitMapToBbox(map: MapLibreMap, bbox: Bbox, options: FitBboxOptions): void {\n  const maxZoom = ceilingFor(map, bbox, options);\n\n  map.fitBounds(\n    [\n      [bbox[0], bbox[1]],\n      [bbox[2], bbox[3]],\n    ],\n    {\n      padding: options.padding,\n      ...(options.duration === undefined ? {} : { duration: options.duration }),\n      ...(maxZoom === undefined ? {} : { maxZoom }),\n    },\n  );\n}\n","/**\n * Clamps a value between a minimum and maximum.\n *\n * @param value - The value to clamp\n * @param min - The minimum allowed value\n * @param max - The maximum allowed value\n * @returns The clamped value\n *\n * @example\n * ```typescript\n * clamp(5, 0, 10);  // returns 5\n * clamp(-5, 0, 10); // returns 0\n * clamp(15, 0, 10); // returns 10\n * ```\n */\nexport function clamp(value: number, min: number, max: number): number {\n  return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Formats a numeric value with appropriate decimal places based on step size.\n *\n * @param value - The value to format\n * @param step - The step size to determine decimal places\n * @returns The formatted value as a string\n *\n * @example\n * ```typescript\n * formatNumericValue(5, 1);     // returns \"5\"\n * formatNumericValue(0.5, 0.1); // returns \"0.5\"\n * formatNumericValue(0.55, 0.01); // returns \"0.55\"\n * ```\n */\nexport function formatNumericValue(value: number, step: number): string {\n  if (step === 0) return value.toString();\n  const decimals = Math.max(0, -Math.floor(Math.log10(step)));\n  return value.toFixed(decimals);\n}\n\n/**\n * Generates a unique ID string.\n *\n * @param prefix - Optional prefix for the ID\n * @returns A unique ID string\n *\n * @example\n * ```typescript\n * generateId('control'); // returns \"control-abc123\"\n * generateId();          // returns \"abc123\"\n * ```\n */\nexport function generateId(prefix?: string): string {\n  const id = Math.random().toString(36).substring(2, 9);\n  return prefix ? `${prefix}-${id}` : id;\n}\n\n/**\n * Debounces a function call.\n *\n * @param fn - The function to debounce\n * @param delay - The delay in milliseconds\n * @returns A debounced version of the function\n *\n * @example\n * ```typescript\n * const debouncedUpdate = debounce(() => updateMap(), 100);\n * window.addEventListener('resize', debouncedUpdate);\n * ```\n */\nexport function debounce<T extends (...args: unknown[]) => void>(\n  fn: T,\n  delay: number\n): (...args: Parameters<T>) => void {\n  let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n  return (...args: Parameters<T>) => {\n    if (timeoutId) {\n      clearTimeout(timeoutId);\n    }\n    timeoutId = setTimeout(() => {\n      fn(...args);\n      timeoutId = null;\n    }, delay);\n  };\n}\n\n/**\n * Throttles a function call.\n *\n * @param fn - The function to throttle\n * @param limit - The minimum time between calls in milliseconds\n * @returns A throttled version of the function\n *\n * @example\n * ```typescript\n * const throttledScroll = throttle(() => handleScroll(), 100);\n * window.addEventListener('scroll', throttledScroll);\n * ```\n */\nexport function throttle<T extends (...args: unknown[]) => void>(\n  fn: T,\n  limit: number\n): (...args: Parameters<T>) => void {\n  let inThrottle = false;\n\n  return (...args: Parameters<T>) => {\n    if (!inThrottle) {\n      fn(...args);\n      inThrottle = true;\n      setTimeout(() => {\n        inThrottle = false;\n      }, limit);\n    }\n  };\n}\n\n/**\n * Creates a CSS class string from an object of class names.\n *\n * @param classes - Object with class names as keys and boolean values\n * @returns A space-separated string of class names\n *\n * @example\n * ```typescript\n * classNames({ active: true, disabled: false, visible: true });\n * // returns \"active visible\"\n * ```\n */\nexport function classNames(classes: Record<string, boolean>): string {\n  return Object.entries(classes)\n    .filter(([, value]) => value)\n    .map(([key]) => key)\n    .join(' ');\n}\n","/**\n * Remote file size probing.\n *\n * DuckDB-WASM's HTTP filesystem handles remote file sizes as 32-bit\n * values; files of 2 GiB or larger fail to open with an opaque\n * \"Cannot read properties of null (reading 'byteLength')\" error.\n * Probing the size up front (before the ~20 MB engine download even\n * starts) turns that into an immediate, actionable message.\n */\n\n/**\n * Largest remote file DuckDB-WASM can open.\n */\nexport const MAX_REMOTE_FILE_BYTES = 2 ** 31 - 1;\n\nconst sizes = new Map<string, number | undefined>();\n\n/**\n * Returns the remote file size from a HEAD request, cached per URL.\n *\n * @param url - The http(s) URL to probe\n * @returns The content length in bytes, or undefined when the HEAD is\n *   blocked or reports no length\n */\nexport async function probeRemoteSize(url: string): Promise<number | undefined> {\n  if (!/^https?:\\/\\//i.test(url)) return undefined;\n  if (!sizes.has(url)) {\n    let size: number | undefined;\n    try {\n      const response = await fetch(url, { method: 'HEAD' });\n      const length = response.headers.get('content-length');\n      if (length) size = Number(length);\n    } catch {\n      // HEAD unavailable (CORS or method blocked); let DuckDB try.\n    }\n    sizes.set(url, size);\n  }\n  return sizes.get(url);\n}\n\n/**\n * Probes a remote file's size and rejects files DuckDB-WASM cannot\n * open (2 GiB or larger).\n *\n * @param url - The http(s) URL to check\n * @returns The content length in bytes, when known\n * @throws Error with an actionable message for oversized files\n */\nexport async function assertRemoteFileSupported(url: string): Promise<number | undefined> {\n  const size = await probeRemoteSize(url);\n  if (size !== undefined && size > MAX_REMOTE_FILE_BYTES) {\n    const gib = (size / 1024 ** 3).toFixed(2);\n    throw new Error(\n      `This file is ${gib} GiB; DuckDB-WASM cannot open remote files of 2 GiB or larger. ` +\n        `Use a smaller file or partition (e.g. split by region).`,\n    );\n  }\n  return size;\n}\n","import type { Map as MapLibreMap, MapLayerMouseEvent } from 'maplibre-gl';\nimport type { FeatureCollection } from 'geojson';\nimport type {\n  RenderMode,\n  VectorControlEvent,\n  VectorControlOptions,\n  VectorDataSource,\n  VectorLayerInfo,\n  VectorLayerOptions,\n  VectorLayerStyle,\n  VectorLayerSelector,\n} from './types';\nimport { VectorLayerSelectionCancelledError } from './errors';\nimport { openLayerPicker, type LayerPickerHandle } from '../ui/layerPicker';\nimport type { EngineProvider } from '../engine/types';\nimport type { VectorSourceDescriptor } from './types';\nimport { detectSource } from '../formats/detect';\nimport { sniffRemoteGeoJSON } from '../formats/geojsonSniff';\nimport { enhanceKmzGeoJSON, prepareKmzIcons } from '../formats/kmzMetadata';\nimport { decideRenderMode } from '../render/renderMode';\nimport {\n  DEFAULT_LABEL_SIZE,\n  DEFAULT_STYLE,\n  applyOpacity,\n  applyStyle,\n  clampOpacity,\n  hasLabels,\n  labelTextField,\n  mapLayerId,\n  pointModeOf,\n} from '../render/styleBuilder';\nimport {\n  addGeoJSONSource,\n  addGeometryLayers,\n  addLabelLayer,\n  addVectorTileSource,\n  clusterOptionsFor,\n  removeLayersAndSource,\n  setLayersVisibility,\n  sourceIdFor,\n} from '../render/mapSources';\nimport { registerTileProvider, tileUrlFor, unregisterTileProvider } from '../tiles/protocol';\nimport {\n  collectFieldNames,\n  crsFromGeoJSON,\n  summarizeFeatureCollection,\n  toFeatureCollection,\n} from '../utils/geometry';\nimport { fitMapToBbox } from '../utils/fit';\nimport { generateId } from '../utils/helpers';\nimport { getMaplibre } from '../utils/maplibre';\nimport { assertRemoteFileSupported } from '../utils/remote';\n\n/**\n * Emits a control event with optional layer/error context.\n */\nexport type LayerManagerEmitter = (\n  type: VectorControlEvent,\n  extra?: { layer?: VectorLayerInfo; error?: Error; message?: string },\n) => void;\n\n/**\n * Dependencies injected into the layer manager.\n */\nexport interface LayerManagerDeps {\n  map: MapLibreMap;\n  options: VectorControlOptions;\n  emit: LayerManagerEmitter;\n  getEngine: EngineProvider;\n}\n\ninterface LayerRecord {\n  info: VectorLayerInfo;\n  source: VectorDataSource;\n  /** Original URL when a host urlLoader materialized the source as a Blob. */\n  remoteUrl?: string;\n  sourceLayer?: string;\n  fileName?: string;\n  /** Sidecar files for a loose shapefile, registered alongside its `.shp`. */\n  companionFiles?: File[];\n  /**\n   * The FeatureCollection backing a geojson-rendered layer, cached so a\n   * structural restyle (pointMode/cluster change) can rebuild the source and\n   * layers without re-fetching or reading it back from the map.\n   */\n  geojson?: FeatureCollection;\n  /** Set once the source has been ingested into the engine */\n  tableName?: string;\n  /**\n   * Globally unique key in the duckdb:// provider registry. Distinct\n   * from the public layer id, which can repeat across controls.\n   */\n  providerKey?: string;\n  /** Per-map-layer picker handlers, for cleanup */\n  pickerHandlers?: PickerHandler[];\n}\n\ninterface PickerHandler {\n  layerId: string;\n  click: (e: MapLayerMouseEvent) => void;\n  enter: () => void;\n  leave: () => void;\n}\n\nconst DEFAULT_MAX_TILE_ZOOM = 16;\n\n/**\n * Builds a SQL-safe table name from a layer id.\n *\n * @param layerId - The vector layer id\n * @returns A sanitized table name\n */\nexport function tableNameFor(layerId: string): string {\n  return `t_${layerId}`.replace(/[^a-zA-Z0-9_]/g, '_');\n}\n\n/**\n * Describes where a data source came from, so hosts can persist and\n * later recreate URL-backed layers (files and objects cannot be\n * recreated from the descriptor).\n *\n * @param source - The data source passed to addData\n * @param sourcePath - Host-meaningful path a File/Blob was read from, echoed\n *   on the descriptor so the host can re-read it on project restore. Ignored\n *   for URL and GeoJSON-object sources.\n * @returns The public source descriptor\n */\nexport function describeSource(\n  source: VectorDataSource,\n  sourcePath?: string,\n): VectorSourceDescriptor {\n  if (typeof source === 'string') {\n    return { kind: 'url', url: source };\n  }\n  const path = sourcePath?.trim() ? sourcePath : undefined;\n  if (typeof File !== 'undefined' && source instanceof File) {\n    return { kind: 'file', fileName: source.name, ...(path ? { path } : {}) };\n  }\n  if (typeof Blob !== 'undefined' && source instanceof Blob) {\n    return { kind: 'file', ...(path ? { path } : {}) };\n  }\n  return { kind: 'geojson' };\n}\n\n/**\n * Detects a loose `.shp` file that cannot be read because its required\n * `.shx`/`.dbf` siblings were not provided.\n *\n * A shapefile is a set of files. A lone `.shp` (or one missing the index or\n * attribute sidecar) makes GDAL fail with an opaque \"GDALOpen() called on\n * x.shp recursively\" error; callers use this to surface an actionable message\n * instead. A zipped shapefile (`.zip`) carries its components, so it is never\n * flagged.\n *\n * @param source - The data source passed to addData.\n * @param options - The layer options, whose `companionFiles` hold the sidecars.\n * @returns True when the source is a `.shp` lacking its `.shx` or `.dbf`.\n */\nexport function isLooseShapefileMissingSiblings(\n  source: VectorDataSource,\n  options: VectorLayerOptions,\n): boolean {\n  if (typeof File === 'undefined' || !(source instanceof File)) return false;\n  if (!/\\.shp$/i.test(source.name)) return false;\n  const extensions = new Set(\n    (options.companionFiles ?? []).map((file) =>\n      file.name.slice(file.name.lastIndexOf('.') + 1).toLowerCase(),\n    ),\n  );\n  return !extensions.has('shx') || !extensions.has('dbf');\n}\n\n/**\n * Owns the vector layers of a control: loading data, creating map\n * sources/layers, visibility, styling, render-mode switching, and\n * cleanup. Communicates with DuckDB only through the injected engine\n * provider, which is resolved lazily on first non-GeoJSON load.\n */\nexport class LayerManager {\n  /**\n   * Carries a materialized URL through multi-layer container expansion without\n   * exposing an internal option on the public addData API.\n   */\n  private readonly _materializedUrls = new WeakMap<object, string>();\n  private _map: MapLibreMap;\n  private _options: VectorControlOptions;\n  private _emit: LayerManagerEmitter;\n  private _getEngine: EngineProvider;\n  private _records = new Map<string, LayerRecord>();\n  private _popup?: { remove(): void };\n  private _popupOwnerId?: string;\n  private _pendingTiles = 0;\n  private _tileStatusTimer?: ReturnType<typeof setTimeout>;\n  // Multi-layer pickers currently on screen (or queued), so dispose() can\n  // close them instead of orphaning a modal in the map container.\n  private _openPickers = new Set<LayerPickerHandle>();\n\n  /**\n   * Creates a layer manager.\n   *\n   * @param deps - Injected dependencies\n   */\n  constructor(deps: LayerManagerDeps) {\n    this._map = deps.map;\n    this._options = deps.options;\n    this._emit = deps.emit;\n    this._getEngine = deps.getEngine;\n  }\n\n  /**\n   * Returns metadata for all loaded layers.\n   */\n  getLayers(): VectorLayerInfo[] {\n    return Array.from(this._records.values(), (record) => ({ ...record.info }));\n  }\n\n  /**\n   * Returns metadata for a single layer.\n   *\n   * @param id - The layer id\n   */\n  getLayer(id: string): VectorLayerInfo | undefined {\n    const record = this._records.get(id);\n    return record ? { ...record.info } : undefined;\n  }\n\n  /**\n   * Recreates every managed source and layer removed by MapLibre's setStyle.\n   * The layer records retain their original data source or engine table, so a\n   * basemap swap can rebuild the presentation without losing user state.\n   */\n  async restoreLayersAfterStyleChange(): Promise<void> {\n    for (const record of this._records.values()) {\n      const sourceExists = Boolean(this._map.getSource(record.info.sourceId));\n      const layersExist = record.info.layerIds.every((id) => Boolean(this._map.getLayer(id)));\n      if (sourceExists && layersExist) continue;\n\n      this._detachPicker(record);\n      if (sourceExists) {\n        for (const id of record.info.layerIds) {\n          if (this._map.getLayer(id)) this._map.removeLayer(id);\n        }\n        record.info.layerIds = addGeometryLayers(this._map, {\n          layerId: record.info.id,\n          geometryType: record.info.geometryType,\n          style: record.info.style,\n          visible: record.info.visible,\n          opacity: record.info.opacity,\n          sourceLayer: record.info.renderMode === 'tiles' ? record.info.id : undefined,\n          beforeId:\n            record.info.beforeId && this._map.getLayer(record.info.beforeId)\n              ? record.info.beforeId\n              : undefined,\n        });\n        this._attachPicker(record);\n        this._emit('layerupdated', { layer: { ...record.info } });\n        continue;\n      }\n      record.info.layerIds = [];\n      if (record.info.renderMode === 'tiles') {\n        await this._presentTiles(record);\n      } else {\n        await this._presentGeoJSON(record);\n      }\n      this._emit('layerupdated', { layer: { ...record.info } });\n    }\n  }\n\n  /**\n   * Materializes a layer's features as a GeoJSON FeatureCollection, so a host\n   * can persist the data of a layer loaded from a local file (which a saved\n   * project cannot otherwise recreate). The data comes from the cached\n   * collection (point geojson layers), the DuckDB table (engine/tiles layers),\n   * or the layer's map source (line/polygon geojson layers). Returns null for\n   * an unknown id, or a layer whose data is not held locally (e.g. a GeoParquet\n   * streamed in place, which is queried from its source per tile).\n   *\n   * @param id - The layer id.\n   * @returns The features as a FeatureCollection, or null when unavailable.\n   */\n  async getLayerGeoJSON(id: string): Promise<FeatureCollection | null> {\n    const record = this._records.get(id);\n    if (!record) return null;\n    if (record.geojson) {\n      return enhanceKmzGeoJSON(\n        record.source,\n        record.geojson,\n        record.fileName ??\n          (record.info.source.kind === 'file' ? record.info.source.fileName : undefined),\n      );\n    }\n    if (record.tableName) {\n      const engine = await this._getEngine();\n      return enhanceKmzGeoJSON(\n        record.source,\n        await engine.exportGeoJSON(record.tableName),\n        record.fileName ??\n          (record.info.source.kind === 'file' ? record.info.source.fileName : undefined),\n      );\n    }\n    // A line/polygon geojson layer keeps no cached copy (to avoid pinning the\n    // heap), but its data lives in the map source it was added with.\n    const source = this._map.getSource(record.info.sourceId);\n    const serialized = source?.serialize() as { data?: unknown } | undefined;\n    const data = serialized?.data;\n    if (data && typeof data === 'object' && (data as FeatureCollection).type) {\n      return data as FeatureCollection;\n    }\n    return null;\n  }\n\n  /**\n   * Reads the non-null values of one layer attribute without materializing\n   * engine-backed geometry. This keeps classification and other\n   * attribute-driven host controls usable for large tiled layers.\n   *\n   * @param id - The layer id.\n   * @param property - An attribute field name.\n   * @returns The values, or null when the layer or field is unavailable.\n   */\n  async getLayerPropertyValues(id: string, property: string): Promise<unknown[] | null> {\n    const record = this._records.get(id);\n    if (!record || !record.info.fields?.includes(property)) return null;\n    if (record.tableName) {\n      const engine = await this._getEngine();\n      return engine.getPropertyValues(record.tableName, property);\n    }\n    const collection = await this.getLayerGeoJSON(id);\n    if (!collection) return null;\n    return collection.features\n      .map((feature) => feature.properties?.[property])\n      .filter((value) => value !== null && value !== undefined);\n  }\n\n  /**\n   * Loads a data source and adds it to the map.\n   *\n   * @param source - URL string, File/Blob, or GeoJSON object\n   * @param options - Layer options\n   * @returns Metadata of the added layer\n   */\n  async addData(\n    source: VectorDataSource,\n    options: VectorLayerOptions = {},\n  ): Promise<VectorLayerInfo> {\n    const detected = detectSource(source, options.format);\n    const id = options.id ?? generateId('vector');\n    if (this._records.has(id)) {\n      throw new Error(`Layer \"${id}\" already exists`);\n    }\n    let remoteUrl =\n      typeof source === 'object' && source !== null\n        ? this._materializedUrls.get(source as object)\n        : undefined;\n    if (\n      typeof source === 'string' &&\n      /^https?:\\/\\//i.test(source) &&\n      this._options.urlLoader\n    ) {\n      remoteUrl = source;\n      this._emit('loading', { message: `Downloading ${detected.name}...` });\n      try {\n        const loaded = await this._options.urlLoader(source);\n        if (!loaded) {\n          remoteUrl = undefined;\n        } else {\n          const isGeoJSON = /(?:^|[/+])(?:geo)?json(?:;|$)/i.test(loaded.type);\n          if (detected.format === 'unknown' && isGeoJSON) detected.format = 'geojson';\n          const fileName =\n            isGeoJSON && !/\\.[a-z0-9]+$/i.test(detected.name)\n              ? `${detected.name}.geojson`\n              : detected.name;\n          source =\n            typeof File !== 'undefined' && loaded instanceof File\n              ? loaded\n              : new File([loaded], fileName, { type: loaded.type });\n          this._materializedUrls.set(source, remoteUrl);\n        }\n      } catch (err) {\n        const error = err instanceof Error ? err : new Error(String(err));\n        this._emit('error', { error });\n        throw error;\n      }\n    }\n\n    // A shapefile is several files. A lone `.shp` (or one missing its `.shx`/\n    // `.dbf` siblings) cannot be read, and GDAL fails with an opaque\n    // \"GDALOpen() called on x.shp recursively\" error. Surface an actionable\n    // message instead, before any engine work, telling the user to select the\n    // companion files too (or load the shapefile as a single `.zip`).\n    if (detected.format === 'shapefile' && isLooseShapefileMissingSiblings(source, options)) {\n      const error = new Error(\n        'A shapefile is a set of files. Select the .shp together with its ' +\n          '.shx and .dbf files (and .prj, .cpg if present), or load the ' +\n          'shapefile as a single .zip archive.',\n      );\n      this._emit('error', { error });\n      throw error;\n    }\n\n    // Extensionless remote URLs (OGC API Features / ArcGIS `f=geojson`, custom\n    // service endpoints with query strings) return GeoJSON the file-name\n    // detector classifies as 'unknown', which would route to the DuckDB engine\n    // and its remote spatial-extension install -- a hang in sandboxed/offline\n    // environments. Sniff the response first so a GeoJSON endpoint stays on the\n    // pure-JS path; the fetched data is reused so it is not re-downloaded.\n    let prefetchedGeoJSON: { collection: FeatureCollection; byteSize?: number } | undefined;\n    if (\n      detected.format === 'unknown' &&\n      !options.format &&\n      options.renderMode !== 'tiles' &&\n      typeof source === 'string' &&\n      !source.startsWith('data:')\n    ) {\n      const sniffed = await sniffRemoteGeoJSON(source);\n      if (sniffed) {\n        detected.format = 'geojson';\n        prefetchedGeoJSON = sniffed;\n      }\n    }\n\n    // Reject remote files DuckDB-WASM cannot open BEFORE the engine\n    // download starts, so the error is immediate.\n    const engineBound = !(detected.format === 'geojson' && options.renderMode !== 'tiles');\n    if (engineBound && typeof source === 'string') {\n      try {\n        await assertRemoteFileSupported(source);\n      } catch (err) {\n        const error = err instanceof Error ? err : new Error(String(err));\n        this._emit('error', { error });\n        throw error;\n      }\n    }\n\n    // Multi-layer containers (GeoPackage tables, KML folders, ...)\n    // expand into one vector layer per source layer.\n    const expanded = await this._maybeExpandLayers(source, options, detected, id);\n    if (expanded) return expanded;\n\n    const name = options.name ?? detected.name;\n    const style: VectorLayerStyle = { ...DEFAULT_STYLE, ...options.style };\n    const visible = options.visible ?? true;\n\n    const record: LayerRecord = {\n      info: {\n        id,\n        name,\n        source: remoteUrl\n          ? { kind: 'url', url: remoteUrl }\n          : describeSource(source, options.sourcePath),\n        format: detected.format,\n        renderMode: 'geojson',\n        geometryType: 'unknown',\n        visible,\n        opacity: clampOpacity(options.opacity ?? 1),\n        picker: options.picker ?? this._options.enablePicker ?? true,\n        ingestMode: options.ingestMode ?? this._options.defaultIngestMode ?? 'table',\n        sourceLayer: options.sourceLayer,\n        sourceCrs: options.sourceCrs?.trim() || undefined,\n        beforeId: options.beforeId ?? this._options.beforeId,\n        style,\n        sourceId: sourceIdFor(id),\n        layerIds: [],\n      },\n      source,\n      remoteUrl,\n      sourceLayer: options.sourceLayer,\n      fileName: typeof File !== 'undefined' && source instanceof File ? source.name : undefined,\n      companionFiles: options.companionFiles,\n    };\n\n    this._emit('loading', { message: `Loading ${name}...` });\n\n    try {\n      if (detected.format === 'geojson' && options.renderMode !== 'tiles') {\n        await this._addGeoJSON(record, options, prefetchedGeoJSON);\n      } else {\n        await this._addViaEngine(record, options);\n      }\n    } catch (err) {\n      const error = err instanceof Error ? err : new Error(String(err));\n      this._emit('error', { error });\n      throw error;\n    }\n\n    this._records.set(id, record);\n    if ((options.fitBounds ?? true) && record.info.bbox) {\n      this._fitBounds(record.info.bbox);\n    }\n    this._emit('layeradded', { layer: { ...record.info } });\n    return { ...record.info };\n  }\n\n  /**\n   * Removes a layer from the map and the engine.\n   *\n   * @param id - The layer id\n   */\n  removeLayer(id: string): void {\n    const record = this._records.get(id);\n    if (!record) return;\n\n    this._detachPicker(record);\n    removeLayersAndSource(this._map, record.info.layerIds, record.info.sourceId);\n    if (record.providerKey) unregisterTileProvider(record.providerKey);\n    if (record.tableName) {\n      const tableName = record.tableName;\n      this._getEngine()\n        .then((engine) => engine.dropTable(tableName))\n        .catch(() => {\n          // The engine is already gone or never loaded; nothing to clean up.\n        });\n    }\n    this._records.delete(id);\n    this._emit('layerremoved', { layer: { ...record.info } });\n  }\n\n  /**\n   * Removes all layers.\n   */\n  removeAll(): void {\n    for (const id of Array.from(this._records.keys())) {\n      this.removeLayer(id);\n    }\n  }\n\n  /**\n   * Shows or hides a layer.\n   *\n   * @param id - The layer id\n   * @param visible - Whether the layer should be visible\n   */\n  setLayerVisibility(id: string, visible: boolean): void {\n    const record = this._records.get(id);\n    if (!record) return;\n    // Structural point-style changes replace the native MapLibre layers. The\n    // cached flag can already match the requested value while a newly rebuilt\n    // heatmap/circle layer has defaulted back to visible, so always reconcile\n    // the current layer ids instead of treating an equal flag as a no-op.\n    setLayersVisibility(this._map, record.info.layerIds, visible);\n    const changed = record.info.visible !== visible;\n    record.info.visible = visible;\n    if (changed) this._emit('layerupdated', { layer: { ...record.info } });\n  }\n\n  /**\n   * Zooms the map to a layer's extent.\n   *\n   * @param id - The layer id\n   */\n  zoomToLayer(id: string): void {\n    const record = this._records.get(id);\n    if (!record?.info.bbox) return;\n    this._fitBounds(record.info.bbox);\n  }\n\n  /**\n   * Applies a style patch to a layer.\n   *\n   * @param id - The layer id\n   * @param patch - Partial style update\n   */\n  setLayerStyle(id: string, patch: Partial<VectorLayerStyle>): void {\n    const record = this._records.get(id);\n    if (!record) return;\n    const prev = record.info.style;\n    const next = { ...prev, ...patch };\n    record.info.style = next;\n    // pointMode (and cluster radius/maxZoom) are structural: they change the\n    // layer types and/or the source's clustering, which setPaintProperty cannot\n    // express, so rebuild the layers instead of patching paint. The rebuild\n    // re-adds the label layer from the current style, so no separate label\n    // handling is needed on that branch.\n    if (this._isStructuralPointChange(record, prev, next)) {\n      // `_rebuildPointLayers` only replaces `record.info.layerIds` once it\n      // resolves (it awaits KMZ icon preparation), so the event has to wait for\n      // it. Emitting synchronously here would report the ids of the layers the\n      // rebuild has just removed, and nothing emits again afterwards: a host\n      // that mirrors `layerIds` to order or toggle the map layers would leave\n      // the new heatmap/cluster layers unmanaged — they keep whatever stacking\n      // the rebuild appended them with, above layers meant to sit over them.\n      // `finally`, not `then`, so a failed rebuild still reports the record's\n      // current state instead of going silent.\n      void this._rebuildPointLayers(record).finally(() => {\n        this._emit('layerupdated', { layer: { ...record.info } });\n      });\n      return;\n    }\n    if (this._isExtrusionToggle(record, prev, next)) {\n      // Flipping extrusion on or off swaps a polygon layer between flat fill and\n      // a fill-extrusion layer, which setPaintProperty cannot express; rebuild\n      // the map layers (the source is unchanged). The rebuild re-adds the label\n      // layer from the current style, so no separate label handling is needed.\n      this._rebuildGeometryLayers(record);\n    } else {\n      applyStyle(this._map, record.info, patch, record.info.opacity);\n      this._applyLabelChange(record, prev, next, patch);\n    }\n    this._emit('layerupdated', { layer: { ...record.info } });\n  }\n\n  /**\n   * Reconciles the attribute label layer after a style patch: adds it when a\n   * labelField is newly set, removes it when cleared, and otherwise applies\n   * the label layout changes (text-field, size, placement, overlap) that\n   * `applyStyle` (which only touches paint) cannot.\n   */\n  private _applyLabelChange(\n    record: LayerRecord,\n    prev: VectorLayerStyle,\n    next: VectorLayerStyle,\n    patch: Partial<VectorLayerStyle>,\n  ): void {\n    const had = hasLabels(prev);\n    const has = hasLabels(next);\n    const labelId = mapLayerId(record.info.id, 'label');\n\n    if (has && (!had || !this._map.getLayer(labelId))) {\n      this._addLabelLayer(record);\n      // The label layer joined layerIds, so re-wire the picker to cover it\n      // (picker handlers are attached per layer id; see _attachPicker).\n      this._refreshPicker(record);\n      return;\n    }\n    if (!has) {\n      if (had && this._map.getLayer(labelId)) {\n        this._map.removeLayer(labelId);\n        record.info.layerIds = record.info.layerIds.filter((id) => id !== labelId);\n        // Drop the now-stale picker handler for the removed label layer.\n        this._refreshPicker(record);\n      }\n      return;\n    }\n\n    // Both before and after have labels: apply the layout-side changes (paint\n    // changes already went through applyStyle).\n    if (patch.labelField !== undefined) {\n      this._map.setLayoutProperty(labelId, 'text-field', labelTextField(next));\n    }\n    if (patch.labelSize !== undefined) {\n      this._map.setLayoutProperty(labelId, 'text-size', next.labelSize ?? DEFAULT_LABEL_SIZE);\n    }\n    if (patch.labelPlacement !== undefined) {\n      this._map.setLayoutProperty(\n        labelId,\n        'symbol-placement',\n        next.labelPlacement === 'line' ? 'line' : 'point',\n      );\n    }\n    if (patch.labelAllowOverlap !== undefined) {\n      const allow = next.labelAllowOverlap ?? false;\n      this._map.setLayoutProperty(labelId, 'text-allow-overlap', allow);\n      this._map.setLayoutProperty(labelId, 'text-ignore-placement', allow);\n    }\n  }\n\n  /**\n   * Adds the attribute label layer for a record and records its id, choosing\n   * the source-layer for tile-rendered layers.\n   */\n  private _addLabelLayer(record: LayerRecord): void {\n    const labelId = mapLayerId(record.info.id, 'label');\n    if (this._map.getLayer(labelId)) return;\n    addLabelLayer(this._map, {\n      layerId: record.info.id,\n      style: record.info.style,\n      visible: record.info.visible,\n      opacity: record.info.opacity,\n      sourceLayer: record.info.renderMode === 'tiles' ? record.info.id : undefined,\n      beforeId: record.info.beforeId,\n    });\n    if (!record.info.layerIds.includes(labelId)) record.info.layerIds.push(labelId);\n  }\n\n  /**\n   * Re-attaches the picker so its handlers cover the current `layerIds` after a\n   * label layer is added or removed at runtime. A no-op when the picker is off.\n   */\n  private _refreshPicker(record: LayerRecord): void {\n    if (!record.info.picker) return;\n    this._detachPicker(record);\n    this._attachPicker(record);\n  }\n\n  /**\n   * Whether a style change requires rebuilding a geojson point layer's map\n   * layers (a pointMode switch, or a cluster radius/maxZoom change while\n   * clustered) rather than a plain paint update.\n   */\n  private _isStructuralPointChange(\n    record: LayerRecord,\n    prev: VectorLayerStyle,\n    next: VectorLayerStyle,\n  ): boolean {\n    if (record.info.renderMode !== 'geojson' || record.info.geometryType !== 'point') {\n      return false;\n    }\n    if (pointModeOf(prev) !== pointModeOf(next)) return true;\n    return (\n      pointModeOf(next) === 'cluster' &&\n      ((prev.clusterRadius ?? 50) !== (next.clusterRadius ?? 50) ||\n        (prev.clusterMaxZoom ?? 14) !== (next.clusterMaxZoom ?? 14))\n    );\n  }\n\n  /**\n   * Whether a style change toggles 3D extrusion on a layer with polygon\n   * geometry, which swaps the flat `fill`/`outline` layers for a single\n   * `fill-extrusion` layer (and back). Such a change is structural — the map\n   * layer types differ — so it cannot be a plain paint update. Restyle edits\n   * made while extrusion stays on (color/height/base/opacity) are paint ops.\n   */\n  private _isExtrusionToggle(\n    record: LayerRecord,\n    prev: VectorLayerStyle,\n    next: VectorLayerStyle,\n  ): boolean {\n    const geometry = record.info.geometryType;\n    if (geometry !== 'polygon' && geometry !== 'mixed' && geometry !== 'unknown') {\n      return false;\n    }\n    return (prev.extrusionEnabled === true) !== (next.extrusionEnabled === true);\n  }\n\n  /**\n   * Rebuilds a layer's map layers from the existing source, so an extrusion\n   * toggle re-creates the polygon layers (flat fill vs fill-extrusion) without\n   * re-fetching or re-adding the source. Preserves the picker.\n   */\n  private _rebuildGeometryLayers(record: LayerRecord): void {\n    this._detachPicker(record);\n    for (const id of record.info.layerIds) {\n      if (this._map.getLayer(id)) this._map.removeLayer(id);\n    }\n    record.info.layerIds = addGeometryLayers(this._map, {\n      layerId: record.info.id,\n      geometryType: record.info.geometryType,\n      style: record.info.style,\n      visible: record.info.visible,\n      opacity: record.info.opacity,\n      sourceLayer: record.info.renderMode === 'tiles' ? record.info.id : undefined,\n      beforeId: record.info.beforeId,\n    });\n    this._attachPicker(record);\n  }\n\n  /**\n   * Rebuilds a geojson point layer's source and map layers from the data\n   * already held by the source, so a pointMode/cluster change takes effect\n   * without re-fetching. Preserves the picker.\n   */\n  private async _rebuildPointLayers(record: LayerRecord): Promise<void> {\n    // Use the cached FeatureCollection: reading it back from the map via\n    // source.serialize() is unreliable for a clustered source.\n    const collection = record.geojson;\n    if (!collection) return;\n    const sourceId = record.info.sourceId;\n    this._detachPicker(record);\n    removeLayersAndSource(this._map, record.info.layerIds, sourceId);\n    addGeoJSONSource(\n      this._map,\n      record.info.id,\n      collection,\n      this._options.attribution,\n      clusterOptionsFor(record.info.geometryType, record.info.style),\n    );\n    const kmlIconImage = await prepareKmzIcons(this._map, collection);\n    record.info.layerIds = addGeometryLayers(this._map, {\n      layerId: record.info.id,\n      geometryType: record.info.geometryType,\n      style: record.info.style,\n      visible: record.info.visible,\n      opacity: record.info.opacity,\n      beforeId: record.info.beforeId,\n      kmlIconImage,\n    });\n    this._attachPicker(record);\n  }\n\n  /**\n   * Sets a layer's master opacity, multiplied into every style opacity\n   * (fill, circle, and line layers alike).\n   *\n   * @param id - The layer id\n   * @param opacity - The new opacity (0-1)\n   */\n  setLayerOpacity(id: string, opacity: number): void {\n    const record = this._records.get(id);\n    if (!record) return;\n    const clamped = clampOpacity(opacity);\n    if (record.info.opacity === clamped) return;\n    record.info.opacity = clamped;\n    applyOpacity(this._map, record.info, record.info.style, clamped);\n    this._emit('layerupdated', { layer: { ...record.info } });\n  }\n\n  /**\n   * Enables or disables the attribute popup for a layer.\n   *\n   * @param id - The layer id\n   * @param enabled - Whether clicking a feature opens a popup\n   */\n  setLayerPicker(id: string, enabled: boolean): void {\n    const record = this._records.get(id);\n    if (!record || record.info.picker === enabled) return;\n    record.info.picker = enabled;\n    this._detachPicker(record);\n    if (enabled) this._attachPicker(record);\n    this._emit('layerupdated', { layer: { ...record.info } });\n  }\n\n  /**\n   * Moves a layer's map layers before another map layer (or to the top\n   * when omitted).\n   *\n   * @param id - The layer id\n   * @param beforeId - Target map layer id, or undefined for the top\n   */\n  setLayerBeforeId(id: string, beforeId?: string): void {\n    const record = this._records.get(id);\n    if (!record) return;\n    const target = beforeId && this._map.getLayer(beforeId) ? beforeId : undefined;\n    // Moving in creation order keeps the group's internal stacking.\n    for (const layerId of record.info.layerIds) {\n      this._map.moveLayer(layerId, target);\n    }\n    record.info.beforeId = target;\n    this._emit('layerupdated', { layer: { ...record.info } });\n  }\n\n  /**\n   * Switches a layer between GeoJSON and dynamic tile rendering.\n   *\n   * @param id - The layer id\n   * @param mode - The requested render mode\n   */\n  async setRenderMode(id: string, mode: RenderMode): Promise<void> {\n    const record = this._records.get(id);\n    if (!record) return;\n\n    const target = decideRenderMode({\n      requested: mode,\n      defaultMode: this._options.defaultRenderMode,\n      featureCount: record.info.featureCount,\n      byteSize: record.info.byteSize,\n      threshold: this._options.autoThreshold,\n    });\n    if (target === record.info.renderMode) return;\n\n    this._emit('loading', { message: `Switching ${record.info.name} to ${target}...` });\n\n    try {\n      this._detachPicker(record);\n      removeLayersAndSource(this._map, record.info.layerIds, record.info.sourceId);\n      if (record.providerKey) unregisterTileProvider(record.providerKey);\n      record.info.layerIds = [];\n\n      if (target === 'tiles') {\n        await this._presentTiles(record);\n      } else {\n        await this._presentGeoJSON(record);\n      }\n    } catch (err) {\n      const error = err instanceof Error ? err : new Error(String(err));\n      this._emit('error', { error });\n      throw error;\n    }\n\n    this._emit('layerupdated', { layer: { ...record.info } });\n  }\n\n  /**\n   * Re-fetches a URL-backed layer's data and re-renders it in place,\n   * preserving the layer id, source id, style, render mode, and stacking\n   * position. File and in-memory GeoJSON sources are static between loads,\n   * so for those the current info is returned unchanged.\n   *\n   * @param id - The layer id\n   * @returns The refreshed layer info, or undefined when no such layer exists\n   */\n  async reloadLayer(id: string): Promise<VectorLayerInfo | undefined> {\n    const record = this._records.get(id);\n    if (!record) return undefined;\n    // Only URL sources can change between loads; files/objects are static.\n    if (typeof record.source !== 'string' && !record.remoteUrl) return { ...record.info };\n\n    this._emit('loading', { message: `Refreshing ${record.info.name}...` });\n\n    try {\n      if (record.remoteUrl && this._options.urlLoader) {\n        const loaded = await this._options.urlLoader(record.remoteUrl);\n        if (loaded) {\n          record.source =\n            typeof File !== 'undefined' && loaded instanceof File\n              ? loaded\n              : new File([loaded], this._defaultFileName(record), { type: loaded.type });\n          this._materializedUrls.set(record.source as object, record.remoteUrl);\n        } else {\n          record.source = record.remoteUrl;\n          record.remoteUrl = undefined;\n        }\n      }\n      // Tear down the current presentation (mirrors setRenderMode).\n      this._detachPicker(record);\n      removeLayersAndSource(this._map, record.info.layerIds, record.info.sourceId);\n      if (record.providerKey) {\n        unregisterTileProvider(record.providerKey);\n        record.providerKey = undefined;\n      }\n      record.info.layerIds = [];\n\n      // Drop the stale engine table so the next ingest re-reads the source.\n      if (record.tableName) {\n        const tableName = record.tableName;\n        record.tableName = undefined;\n        const engine = await this._getEngine();\n        await engine.dropTable(tableName).catch(() => {\n          // Table already gone; nothing to clean up.\n        });\n      }\n\n      // Re-run the load pipeline, preserving the resolved render mode so a\n      // refresh does not flip a tiles layer to geojson (or vice versa).\n      const reloadOptions: VectorLayerOptions = {\n        renderMode: record.info.renderMode,\n        ingestMode: record.info.ingestMode,\n        sourceLayer: record.sourceLayer,\n        sourceCrs: record.info.sourceCrs,\n      };\n      if (record.info.format === 'geojson' && record.info.renderMode !== 'tiles') {\n        await this._addGeoJSON(record, reloadOptions);\n      } else {\n        await this._addViaEngine(record, reloadOptions);\n      }\n    } catch (err) {\n      const error = err instanceof Error ? err : new Error(String(err));\n      this._emit('error', { error });\n      throw error;\n    }\n\n    this._emit('layerupdated', { layer: { ...record.info } });\n    return { ...record.info };\n  }\n\n  /**\n   * Removes all layers and map resources without emitting events.\n   * Called when the control is removed from the map.\n   */\n  dispose(): void {\n    for (const record of this._records.values()) {\n      this._detachPicker(record);\n      removeLayersAndSource(this._map, record.info.layerIds, record.info.sourceId);\n      if (record.providerKey) unregisterTileProvider(record.providerKey);\n    }\n    this._records.clear();\n    // A picker still on screen belongs to the map container, which outlives\n    // the control; close it so no modal is left over the map.\n    for (const picker of this._openPickers) picker.close();\n    this._openPickers.clear();\n    this._popup?.remove();\n    this._popup = undefined;\n    if (this._tileStatusTimer) {\n      clearTimeout(this._tileStatusTimer);\n      this._tileStatusTimer = undefined;\n    }\n  }\n\n  /**\n   * Expands a multi-layer container into one vector layer per selected\n   * source layer, when the source is engine-readable, no sourceLayer was\n   * requested, and the container reports more than one layer.\n   *\n   * Which layers those are comes from {@link VectorLayerOptions.sourceLayers}\n   * when the caller named them, otherwise from the layer selector (the\n   * built-in picker unless the host replaced or disabled it), otherwise all\n   * of them.\n   *\n   * @returns The first created layer's info, or null when the source\n   *   is single-layer (callers continue with the normal flow)\n   * @throws VectorLayerSelectionCancelledError when the user dismissed the\n   *   picker without choosing a layer.\n   */\n  private async _maybeExpandLayers(\n    source: VectorDataSource,\n    options: VectorLayerOptions,\n    detected: { format: VectorLayerInfo['format']; name: string },\n    id: string,\n  ): Promise<VectorLayerInfo | null> {\n    // Single-layer by construction: native readers and the pure-JS\n    // GeoJSON path. Explicit sourceLayer means the caller chose.\n    const singleLayerFormats = ['geojson', 'geoparquet', 'csv'];\n    if (options.sourceLayer || singleLayerFormats.includes(detected.format)) return null;\n\n    const engine = await this._getEngine();\n    const engineSource = await this._engineSource(source);\n    const layerNames = await engine.listLayers(engineSource, tableNameFor(id), {\n      format: detected.format,\n      fileName:\n        typeof File !== 'undefined' && source instanceof File ? source.name : undefined,\n      // A loose shapefile must register its sidecars on this first probe too:\n      // the engine caches the registration by source, so a companion-less\n      // probe would leave the cached `.shp` unreadable for the later ingest.\n      companionFiles: options.companionFiles,\n    });\n    if (layerNames.length <= 1) return null;\n\n    const sourceName = options.name ?? detected.name;\n    const selected = await this._selectContainerLayers(layerNames, options, detected, sourceName);\n\n    this._emit('loading', {\n      message:\n        selected.length === 1\n          ? `Loading 1 layer from ${sourceName}...`\n          : `Loading ${selected.length} layers from ${sourceName}...`,\n    });\n\n    const infos: VectorLayerInfo[] = [];\n    // The container-level selection is already resolved, so it is dropped from\n    // the per-layer options; each sub-load names its single `sourceLayer`.\n    const layerOptions: VectorLayerOptions = { ...options };\n    delete layerOptions.sourceLayers;\n    for (const layerName of selected) {\n      const subId = `${id}-${layerName.replace(/[^a-zA-Z0-9_-]/g, '_')}`;\n      infos.push(\n        await this.addData(source, {\n          ...layerOptions,\n          id: subId,\n          name: layerName,\n          sourceLayer: layerName,\n          fitBounds: false,\n        }),\n      );\n    }\n\n    // Zoom once to the combined extent of all created layers.\n    if (options.fitBounds ?? true) {\n      const boxes = infos.map((info) => info.bbox).filter(Boolean) as Array<\n        [number, number, number, number]\n      >;\n      if (boxes.length > 0) {\n        this._fitBounds([\n          Math.min(...boxes.map((b) => b[0])),\n          Math.min(...boxes.map((b) => b[1])),\n          Math.max(...boxes.map((b) => b[2])),\n          Math.max(...boxes.map((b) => b[3])),\n        ]);\n      }\n    }\n\n    return infos[0];\n  }\n\n  /**\n   * Resolves which layers of a multi-layer container to load.\n   *\n   * An explicit `sourceLayers` list wins; otherwise the layer selector runs\n   * (the built-in modal picker unless the host replaced it, or `false`\n   * disabled prompting); otherwise every layer is loaded. Whatever the source,\n   * the result is intersected with the container's real layers and ordered by\n   * the container, so a selector cannot invent a layer or reorder the load.\n   *\n   * @throws VectorLayerSelectionCancelledError when the selector returned an\n   *   empty selection (the user dismissed the picker).\n   */\n  private async _selectContainerLayers(\n    layerNames: string[],\n    options: VectorLayerOptions,\n    detected: { format: VectorLayerInfo['format'] },\n    sourceName: string,\n  ): Promise<string[]> {\n    const inContainerOrder = (names: readonly string[]): string[] => {\n      const wanted = new Set(names.map((name) => name.toLowerCase()));\n      return layerNames.filter((name) => wanted.has(name.toLowerCase()));\n    };\n\n    if (options.sourceLayers) {\n      const requested = inContainerOrder(options.sourceLayers);\n      if (requested.length === 0) {\n        throw new Error(\n          `None of the requested layers (${options.sourceLayers.join(', ')}) exist in ` +\n            `${sourceName}. Available layers: ${layerNames.join(', ')}.`,\n        );\n      }\n      return requested;\n    }\n\n    const selector = this._layerSelector();\n    if (!selector) return layerNames;\n\n    const chosen = await selector(layerNames, { sourceName, format: detected.format });\n    // null/undefined means \"no opinion\": keep the load-everything default so a\n    // host selector that only handles some formats can defer on the rest.\n    if (chosen == null) return layerNames;\n    const selected = inContainerOrder(chosen);\n    if (selected.length === 0) {\n      throw new VectorLayerSelectionCancelledError(\n        `No layers were selected from ${sourceName}.`,\n      );\n    }\n    return selected;\n  }\n\n  /**\n   * The layer selector in force: the host's when it supplied one, none when it\n   * set `selectLayers: false` (load every layer), else the built-in modal\n   * picker rendered over the map container.\n   */\n  private _layerSelector(): VectorLayerSelector | null {\n    const configured = this._options.selectLayers;\n    if (configured === false) return null;\n    if (configured) return configured;\n    return (layers, context) => {\n      const container = this._map.getContainer?.();\n      // No container to render into (a headless/mock map): fall back to\n      // loading every layer rather than blocking on a modal nobody can see.\n      if (!container) return null;\n      const picker = openLayerPicker({ container, layers, sourceName: context.sourceName });\n      this._openPickers.add(picker);\n      return picker.selection.finally(() => this._openPickers.delete(picker));\n    };\n  }\n\n  /**\n   * Loads a GeoJSON source entirely in JavaScript (no DuckDB), falling\n   * back to the engine when auto mode trips the size thresholds.\n   *\n   * @param prefetched - A collection already fetched by the URL GeoJSON\n   *   sniff, reused so an extensionless GeoJSON endpoint is not requested\n   *   twice.\n   */\n  private async _addGeoJSON(\n    record: LayerRecord,\n    options: VectorLayerOptions,\n    prefetched?: { collection: FeatureCollection; byteSize?: number },\n  ): Promise<void> {\n    const resolved = prefetched ?? (await this._resolveGeoJSON(record.source));\n    const { byteSize } = resolved;\n    let collection = resolved.collection;\n    const summary = summarizeFeatureCollection(collection);\n\n    record.info.featureCount = summary.featureCount;\n    record.info.byteSize = byteSize;\n    record.info.bbox = summary.bbox;\n    record.info.geometryType = summary.geometryType;\n    record.info.fields = collectFieldNames(collection);\n\n    const mode = decideRenderMode({\n      requested: options.renderMode,\n      defaultMode: this._options.defaultRenderMode,\n      featureCount: summary.featureCount,\n      byteSize,\n      threshold: this._options.autoThreshold,\n    });\n\n    if (mode === 'tiles') {\n      // The tile path re-reads the original source through the DuckDB engine,\n      // which reprojects to WGS84 from the source metadata as part of ingest, so\n      // a projected collection is handled there without the in-memory reproject\n      // below (and its metres bbox above is replaced by the engine's).\n      await this._presentTiles(record);\n      return;\n    }\n\n    // A projected GeoJSON declares its CRS via a legacy `crs` member and carries\n    // raw projected coordinates (metres) that MapLibre cannot render, so spin up\n    // the DuckDB engine (only in this case, keeping the WGS84 fast path\n    // engine-free) and reproject to EPSG:4326 before rendering. Without this the\n    // raw coordinates trip MapLibre's \"Invalid LngLat\" guard in the fitBounds\n    // that follows, and the panel is left stuck loading.\n    const sourceCrs = crsFromGeoJSON(collection);\n    if (sourceCrs) {\n      this._emit('loading', { message: `Reprojecting ${record.info.name} to WGS84...` });\n      const engine = await this._getEngine();\n      collection = await engine.reprojectGeoJSON(collection, sourceCrs);\n      const reprojectedSummary = summarizeFeatureCollection(collection);\n      // Replace the projected-metres bbox with the WGS84 extent so the caller's\n      // fitBounds receives valid lon/lat.\n      record.info.bbox = reprojectedSummary.bbox;\n    }\n\n    record.info.renderMode = 'geojson';\n    // Only point layers use the cached collection (for a pointMode rebuild), so\n    // don't pin a full copy of polygon/line data in the JS heap.\n    record.geojson = summary.geometryType === 'point' ? collection : undefined;\n    addGeoJSONSource(\n      this._map,\n      record.info.id,\n      collection,\n      this._options.attribution,\n      clusterOptionsFor(summary.geometryType, record.info.style),\n    );\n    const kmlIconImage = await prepareKmzIcons(this._map, collection);\n    record.info.layerIds = addGeometryLayers(this._map, {\n      layerId: record.info.id,\n      geometryType: summary.geometryType,\n      style: record.info.style,\n      visible: record.info.visible,\n      opacity: record.info.opacity,\n      beforeId: record.info.beforeId,\n      kmlIconImage,\n    });\n    this._attachPicker(record);\n  }\n\n  /**\n   * Loads a source through the DuckDB engine and presents it as GeoJSON\n   * or dynamic tiles based on the resolved render mode.\n   */\n  private async _addViaEngine(record: LayerRecord, options: VectorLayerOptions): Promise<void> {\n    const summary = await this._ingest(record);\n\n    record.info.featureCount = summary.featureCount;\n    record.info.byteSize = summary.byteSize ?? record.info.byteSize;\n    record.info.bbox = summary.bbox;\n    record.info.geometryType = summary.geometryType;\n\n    const mode = decideRenderMode({\n      requested: options.renderMode,\n      defaultMode: this._options.defaultRenderMode,\n      featureCount: summary.featureCount,\n      byteSize: record.info.byteSize,\n      threshold: this._options.autoThreshold,\n    });\n\n    if (mode === 'tiles') {\n      await this._presentTiles(record);\n    } else {\n      await this._presentGeoJSON(record);\n    }\n  }\n\n  /**\n   * Ingests the record's source into the engine, reusing an existing\n   * table when present.\n   */\n  private async _ingest(record: LayerRecord) {\n    const engine = await this._getEngine();\n    const tableName = tableNameFor(record.info.id);\n    const source = await this._engineSource(record.source);\n    this._emit('loading', {\n      message:\n        record.info.ingestMode === 'stream'\n          ? `Opening ${record.info.name} (streaming, reading metadata)...`\n          : `Reading ${record.info.name} into DuckDB...`,\n    });\n    const summary = await engine.ingest(source, tableName, {\n      format: record.info.format,\n      sourceLayer: record.sourceLayer,\n      sourceCrs: record.info.sourceCrs,\n      fileName: record.fileName ?? this._defaultFileName(record),\n      mode: record.info.ingestMode,\n      companionFiles: record.companionFiles,\n    });\n    record.tableName = summary.tableName;\n    record.info.fields = summary.fields;\n    // The engine falls back to a table for formats streaming\n    // does not apply to.\n    record.info.ingestMode = summary.streamed ? 'stream' : 'table';\n    return summary;\n  }\n\n  /**\n   * Presents a record as a dynamic tile layer, ingesting it first when\n   * needed.\n   */\n  private async _presentTiles(record: LayerRecord): Promise<void> {\n    const engine = await this._getEngine();\n    if (!record.tableName) {\n      const summary = await this._ingest(record);\n      record.info.featureCount = summary.featureCount;\n      record.info.bbox = summary.bbox ?? record.info.bbox;\n      record.info.geometryType =\n        summary.geometryType !== 'unknown' ? summary.geometryType : record.info.geometryType;\n    }\n    const tableName = record.tableName!;\n    if (record.info.ingestMode !== 'stream') {\n      this._emit('loading', {\n        message: `Indexing ${record.info.name} for tiles (reprojecting + R-Tree)...`,\n      });\n    }\n    await engine.prepareTiles(tableName);\n\n    const id = record.info.id;\n    // The provider registry is process-wide; key it by a generated\n    // unique value so equal layer ids on two controls cannot collide.\n    const providerKey = record.providerKey ?? generateId(`${id}-tiles`);\n    record.providerKey = providerKey;\n    await registerTileProvider(providerKey, (z, x, y, signal) =>\n      this._trackTileActivity(engine.getTile(tableName, id, z, x, y, signal)),\n    );\n\n    record.info.renderMode = 'tiles';\n    // Tiles never rebuild from a cached collection; drop any copy from a prior\n    // geojson render so it isn't pinned in the heap.\n    record.geojson = undefined;\n    addVectorTileSource(this._map, id, {\n      tileUrl: tileUrlFor(providerKey),\n      maxzoom: this._options.maxTileZoom ?? DEFAULT_MAX_TILE_ZOOM,\n      bounds: record.info.bbox,\n      attribution: this._options.attribution,\n    });\n    record.info.layerIds = addGeometryLayers(this._map, {\n      layerId: id,\n      geometryType: record.info.geometryType,\n      style: record.info.style,\n      visible: record.info.visible,\n      opacity: record.info.opacity,\n      sourceLayer: id,\n      beforeId: record.info.beforeId,\n    });\n    this._attachPicker(record);\n  }\n\n  /**\n   * Presents a record as a GeoJSON layer, exporting from the engine when\n   * the source was ingested, or re-parsing the original source.\n   */\n  private async _presentGeoJSON(record: LayerRecord): Promise<void> {\n    let collection: FeatureCollection;\n    if (record.tableName) {\n      const engine = await this._getEngine();\n      this._emit('loading', { message: `Converting ${record.info.name} to GeoJSON...` });\n      collection = await engine.exportGeoJSON(record.tableName);\n      collection = await enhanceKmzGeoJSON(\n        record.source,\n        collection,\n        record.fileName ??\n          (record.info.source.kind === 'file' ? record.info.source.fileName : undefined),\n      );\n    } else {\n      collection = (await this._resolveGeoJSON(record.source)).collection;\n    }\n\n    if (record.info.geometryType === 'unknown') {\n      record.info.geometryType = summarizeFeatureCollection(collection).geometryType;\n    }\n    record.info.fields = collectFieldNames(collection);\n\n    record.info.renderMode = 'geojson';\n    // Only point layers use the cached collection (for a pointMode rebuild).\n    record.geojson = record.info.geometryType === 'point' ? collection : undefined;\n    addGeoJSONSource(\n      this._map,\n      record.info.id,\n      collection,\n      this._options.attribution,\n      clusterOptionsFor(record.info.geometryType, record.info.style),\n    );\n    const kmlIconImage = await prepareKmzIcons(this._map, collection);\n    record.info.layerIds = addGeometryLayers(this._map, {\n      layerId: record.info.id,\n      geometryType: record.info.geometryType,\n      style: record.info.style,\n      visible: record.info.visible,\n      opacity: record.info.opacity,\n      beforeId: record.info.beforeId,\n      kmlIconImage,\n    });\n    this._attachPicker(record);\n  }\n\n  /**\n   * Resolves a data source to a FeatureCollection without DuckDB.\n   */\n  private async _resolveGeoJSON(\n    source: VectorDataSource,\n  ): Promise<{ collection: FeatureCollection; byteSize?: number }> {\n    if (typeof source === 'string') {\n      const response = await fetch(source);\n      if (!response.ok) {\n        throw new Error(`Failed to fetch ${source}: ${response.status} ${response.statusText}`);\n      }\n      const text = await response.text();\n      return { collection: toFeatureCollection(JSON.parse(text)), byteSize: text.length };\n    }\n\n    if (typeof Blob !== 'undefined' && source instanceof Blob) {\n      const text = await source.text();\n      return { collection: toFeatureCollection(JSON.parse(text)), byteSize: source.size };\n    }\n\n    return { collection: toFeatureCollection(source as Exclude<VectorDataSource, string | Blob>) };\n  }\n\n  /**\n   * Converts a data source to something the engine can register\n   * (GeoJSON objects and data: URLs become Blobs - DuckDB/GDAL cannot\n   * fetch data: URLs).\n   */\n  private async _engineSource(source: VectorDataSource): Promise<string | File | Blob> {\n    if (typeof source === 'string') {\n      if (source.startsWith('data:')) {\n        return (await fetch(source)).blob();\n      }\n      return source;\n    }\n    if (typeof Blob !== 'undefined' && source instanceof Blob) return source;\n    return new Blob([JSON.stringify(source)], { type: 'application/geo+json' });\n  }\n\n  /**\n   * Picks a registration file name for sources without one, using an\n   * extension matching the format so readers can sniff the type.\n   */\n  private _defaultFileName(record: LayerRecord): string {\n    const extensions: Record<string, string> = {\n      geojson: 'geojson',\n      geoparquet: 'parquet',\n      geopackage: 'gpkg',\n      shapefile: 'zip',\n      flatgeobuf: 'fgb',\n      csv: 'csv',\n    };\n    const format = record.info.format;\n    const ext = extensions[format] ?? (format !== 'unknown' ? format : 'bin');\n    return `${tableNameFor(record.info.id)}.${ext}`;\n  }\n\n  /**\n   * Attaches click-to-inspect handlers to a layer's map layers,\n   * opening a popup with the clicked feature's attributes.\n   */\n  private _attachPicker(record: LayerRecord): void {\n    if (!record.info.picker) return;\n    record.pickerHandlers = record.info.layerIds.map((layerId) => {\n      const click = (e: MapLayerMouseEvent) => {\n        const feature = e.features?.[0];\n        if (feature) {\n          void this._showPopup(record.info, e.lngLat, feature.properties ?? {});\n        }\n      };\n      const enter = () => {\n        this._map.getCanvas().style.cursor = 'pointer';\n      };\n      const leave = () => {\n        this._map.getCanvas().style.cursor = '';\n      };\n      this._map.on('click', layerId, click);\n      this._map.on('mouseenter', layerId, enter);\n      this._map.on('mouseleave', layerId, leave);\n      return { layerId, click, enter, leave };\n    });\n  }\n\n  /**\n   * Removes the picker handlers of a layer.\n   */\n  private _detachPicker(record: LayerRecord): void {\n    for (const handler of record.pickerHandlers ?? []) {\n      this._map.off('click', handler.layerId, handler.click);\n      this._map.off('mouseenter', handler.layerId, handler.enter);\n      this._map.off('mouseleave', handler.layerId, handler.leave);\n    }\n    record.pickerHandlers = undefined;\n    // Close a popup owned by this layer so stale attributes do not\n    // linger after removal or a render-mode switch.\n    if (this._popupOwnerId === record.info.id) {\n      this._popup?.remove();\n      this._popup = undefined;\n      this._popupOwnerId = undefined;\n    }\n  }\n\n  /** Opens (or replaces) the attribute popup for a clicked feature. */\n  private async _showPopup(\n    info: Pick<VectorLayerInfo, 'id' | 'name'>,\n    lngLat: { lng: number; lat: number },\n    properties: Record<string, unknown>,\n  ): Promise<void> {\n    const container = document.createElement('div');\n    container.className = 'vector-control-popup';\n\n    const title = document.createElement('div');\n    title.className = 'vector-control-popup-title';\n    title.textContent = info.name;\n    container.appendChild(title);\n\n    const entries = Object.entries(properties).filter(([key]) => !key.startsWith('__geolibre_'));\n    if (entries.length === 0) {\n      const empty = document.createElement('div');\n      empty.className = 'vector-control-popup-empty';\n      empty.textContent = 'No attributes';\n      container.appendChild(empty);\n    } else {\n      const table = document.createElement('table');\n      table.className = 'vector-control-popup-table';\n      for (const [key, value] of entries) {\n        const row = table.insertRow();\n        const keyCell = row.insertCell();\n        keyCell.className = 'vector-control-popup-key';\n        keyCell.textContent = key;\n        const valueCell = row.insertCell();\n        if (\n          key.toLowerCase() === 'description' &&\n          typeof value === 'string' &&\n          /<[^>]+>/.test(value)\n        ) {\n          const parsed = new DOMParser().parseFromString(value, 'text/html');\n          const allowed = new Set([\n            'a',\n            'b',\n            'br',\n            'div',\n            'em',\n            'i',\n            'p',\n            'span',\n            'strong',\n            'table',\n            'tbody',\n            'td',\n            'th',\n            'thead',\n            'tr',\n          ]);\n          const copy = (node: Node, parent: Node): void => {\n            if (node.nodeType === Node.TEXT_NODE) {\n              parent.appendChild(document.createTextNode(node.textContent ?? ''));\n              return;\n            }\n            if (!(node instanceof Element)) return;\n            const tag = node.localName.toLowerCase();\n            if (tag === 'script' || tag === 'style' || tag === 'head' || tag === 'meta') return;\n            if (!allowed.has(tag)) {\n              for (const childNode of node.childNodes) copy(childNode, parent);\n              return;\n            }\n            const element = document.createElement(tag);\n            if (tag === 'a') {\n              const href = node.getAttribute('href')?.trim();\n              if (href && /^(https?:|mailto:)/i.test(href)) {\n                element.setAttribute('href', href);\n                element.setAttribute('target', '_blank');\n                element.setAttribute('rel', 'noopener noreferrer');\n              }\n            }\n            for (const childNode of node.childNodes) copy(childNode, element);\n            parent.appendChild(element);\n          };\n          for (const childNode of parsed.body.childNodes) copy(childNode, valueCell);\n        } else {\n          valueCell.textContent = value === null || value === undefined ? '' : String(value);\n        }\n      }\n      container.appendChild(table);\n    }\n\n    const maplibre = await getMaplibre();\n    this._popup?.remove();\n    const popup = new maplibre.Popup({ closeButton: true, maxWidth: '520px' });\n    popup.setLngLat([lngLat.lng, lngLat.lat]);\n    popup.setDOMContent(container);\n    popup.addTo(this._map);\n    this._popup = popup;\n    this._popupOwnerId = info.id;\n  }\n\n  /**\n   * Surfaces tile generation progress through 'loading' events: shows\n   * a pending count while tile queries run and clears the status\n   * shortly after the queue drains (the delay avoids flicker between\n   * consecutive tiles).\n   */\n  private _trackTileActivity(task: Promise<Uint8Array>): Promise<Uint8Array> {\n    this._pendingTiles += 1;\n    if (this._tileStatusTimer) {\n      clearTimeout(this._tileStatusTimer);\n      this._tileStatusTimer = undefined;\n    }\n    this._emit('loading', { message: `Generating tiles (${this._pendingTiles} pending)...` });\n\n    const settle = () => {\n      this._pendingTiles -= 1;\n      if (this._pendingTiles === 0) {\n        this._tileStatusTimer = setTimeout(() => {\n          this._tileStatusTimer = undefined;\n          this._emit('loading', { message: '' });\n        }, 400);\n      } else {\n        this._emit('loading', { message: `Generating tiles (${this._pendingTiles} pending)...` });\n      }\n    };\n\n    return task.then(\n      (value) => {\n        settle();\n        return value;\n      },\n      (err) => {\n        settle();\n        throw err;\n      },\n    );\n  }\n\n  private _fitBounds(bbox: [number, number, number, number]): void {\n    fitMapToBbox(this._map, bbox, { padding: 40, duration: 600, maxZoom: 16 });\n  }\n}\n","import type { VectorFormat } from '../core/types';\n\n/**\n * Maximum number of features encoded into a single tile.\n */\nexport const TILE_FEATURE_LIMIT = 50_000;\n\n/**\n * Quotes a SQL identifier.\n *\n * @param name - Identifier to quote\n * @returns The double-quoted identifier\n */\nexport function quoteIdent(name: string): string {\n  return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Quotes a SQL string literal.\n *\n * @param value - String value to quote\n * @returns The single-quoted literal\n */\nexport function quoteLiteral(value: string): string {\n  return `'${value.replace(/'/g, \"''\")}'`;\n}\n\n/**\n * Builds the reader expression for a registered file or URL.\n *\n * GeoParquet and CSV use DuckDB's native readers; everything else goes\n * through the spatial extension's ST_Read (GDAL).\n *\n * @param format - The source format\n * @param path - Registered file name or URL\n * @param sourceLayer - Optional layer inside multi-layer containers\n * @returns The FROM-clause reader expression\n */\nexport function readerFor(format: VectorFormat, path: string, sourceLayer?: string): string {\n  switch (format) {\n    case 'geoparquet':\n      return `read_parquet(${quoteLiteral(path)})`;\n    case 'csv':\n      return `read_csv(${quoteLiteral(path)})`;\n    default: {\n      const layerArg = sourceLayer ? `, layer = ${quoteLiteral(sourceLayer)}` : '';\n      return `ST_Read(${quoteLiteral(path)}${layerArg})`;\n    }\n  }\n}\n\n/**\n * Builds the GDAL virtual path for a source, wrapping zip archives in\n * /vsizip/ so zipped shapefiles can be read directly.\n *\n * @param format - The source format\n * @param path - Registered file name or URL\n * @returns The path to hand to ST_Read\n */\nexport function gdalPath(format: VectorFormat, path: string): string {\n  if (format === 'shapefile' && /\\.zip$/i.test(path.split(/[?#]/)[0])) {\n    const prefix = /^https?:\\/\\//i.test(path) ? '/vsizip//vsicurl/' : '/vsizip/';\n    return `${prefix}${path}`;\n  }\n  return path;\n}\n\n/**\n * SQL describing the columns a relation produces (name and type),\n * without materializing it.\n *\n * @param relation - A quoted table name or reader expression\n * @returns The query text\n */\nexport function columnsQueryFromDescribe(relation: string): string {\n  return `DESCRIBE SELECT * FROM ${relation}`;\n}\n\nexport type GeometryEncoding = 'geometry' | 'wkb' | 'base64-wkb';\n\nexport interface ReaderColumnInfo {\n  name: string;\n  type: string;\n}\n\nexport interface DetectedGeometryColumn {\n  name: string;\n  encoding: GeometryEncoding;\n  requiresBase64WkbValidation?: boolean;\n  base64WkbCandidates?: string[];\n}\n\nconst WKB_GEOMETRY_COLUMN_NAMES = [\n  'geometry',\n  'geom',\n  'wkb_geometry',\n  'geometry_wkb',\n  'geom_wkb',\n  'wkb',\n];\n\nfunction wkbNameRank(name: string): number {\n  const rank = WKB_GEOMETRY_COLUMN_NAMES.indexOf(name.toLowerCase());\n  return rank === -1 ? Number.MAX_SAFE_INTEGER : rank;\n}\n\n/**\n * Finds the geometry column produced by a reader. Native DuckDB GEOMETRY\n * columns win; plain Parquet fallbacks may carry WKB as bytes or as a\n * base64-encoded string in a well-known geometry column. String candidates\n * must be value-probed before SQL generation because geometry-like names are\n * sometimes ordinary attributes.\n *\n * @param columns - Column names and types from DESCRIBE\n * @returns Detected geometry column, if one is recognizable\n */\nexport function detectGeometryColumn(\n  columns: ReaderColumnInfo[],\n): DetectedGeometryColumn | undefined {\n  const native = columns.find((column) => column.type.toUpperCase().startsWith('GEOMETRY'));\n  if (native) return { name: native.name, encoding: 'geometry' };\n\n  const sortedWkbCandidates = columns\n    .filter((column) => wkbNameRank(column.name) !== Number.MAX_SAFE_INTEGER)\n    .sort((a, b) => wkbNameRank(a.name) - wkbNameRank(b.name));\n  const binaryWkb = sortedWkbCandidates.find((column) =>\n    /^(BLOB|BINARY|VARBINARY)/i.test(column.type),\n  );\n  if (binaryWkb) return { name: binaryWkb.name, encoding: 'wkb' };\n\n  const base64WkbCandidates = sortedWkbCandidates\n    .filter((column) => /^(VARCHAR|TEXT|STRING)/i.test(column.type))\n    .map((column) => column.name);\n  if (base64WkbCandidates.length > 0) {\n    return {\n      name: base64WkbCandidates[0],\n      encoding: 'base64-wkb',\n      requiresBase64WkbValidation: true,\n      base64WkbCandidates,\n    };\n  }\n  return undefined;\n}\n\n/**\n * SQL creating the ingest table from a reader, normalizing the geometry\n * column to `geom`.\n *\n * @param tableName - The table to create\n * @param reader - Reader expression from {@link readerFor}\n * @param geometryColumn - Name of the source geometry column\n * @returns The statement text\n */\nexport function createTableSql(\n  tableName: string,\n  reader: string,\n  geometryColumn: string,\n): string {\n  const rename =\n    geometryColumn === 'geom'\n      ? ''\n      : ` RENAME (${quoteIdent(geometryColumn)} AS geom)`;\n  return `CREATE OR REPLACE TABLE ${quoteIdent(tableName)} AS SELECT *${rename} FROM ${reader}`;\n}\n\nfunction wkbGeometryExpression(geometry: DetectedGeometryColumn): string {\n  if (geometry.requiresBase64WkbValidation) {\n    throw new Error('Base64 WKB geometry candidates must be validated before SQL generation.');\n  }\n  const column = quoteIdent(geometry.name);\n  const wkb = geometry.encoding === 'base64-wkb' ? `from_base64(${column})` : column;\n  return `ST_GeomFromWKB(${wkb})`;\n}\n\n/**\n * Wraps a geometry expression in `ST_Transform` to WGS84 when a non-WGS84\n * `sourceCrs` was resolved, so the rest of the pipeline (tiles, export) can\n * assume EPSG:4326. Passes the expression through unchanged when `sourceCrs` is\n * null (already WGS84, or CRS unknown). `always_xy` keeps lon/lat axis order.\n *\n * @param geomExpr - The source geometry SQL expression\n * @param sourceCrs - `AUTHORITY:CODE` or a WKT string ST_Transform accepts, or null\n * @returns The (possibly reprojected) geometry expression\n */\nfunction reprojectToWgs84Sql(geomExpr: string, sourceCrs: string | null): string {\n  return sourceCrs\n    ? `ST_Transform(${geomExpr}, ${quoteLiteral(sourceCrs)}, 'EPSG:4326', always_xy := true)`\n    : geomExpr;\n}\n\nfunction createRelationFromGeometrySql(\n  relationKind: 'TABLE' | 'VIEW',\n  tableName: string,\n  reader: string,\n  geometry: DetectedGeometryColumn,\n  sourceCrs: string | null = null,\n): string {\n  // A native GEOMETRY column that needs no reprojection keeps the cheap\n  // `* RENAME` form (no per-row expression).\n  if (geometry.encoding === 'geometry' && !sourceCrs) {\n    return relationKind === 'TABLE'\n      ? createTableSql(tableName, reader, geometry.name)\n      : createViewSql(tableName, reader, geometry.name);\n  }\n  const rawGeom =\n    geometry.encoding === 'geometry'\n      ? quoteIdent(geometry.name)\n      : wkbGeometryExpression(geometry);\n  return (\n    `CREATE OR REPLACE ${relationKind} ${quoteIdent(tableName)} AS ` +\n    `SELECT * EXCLUDE (${quoteIdent(geometry.name)}), ` +\n    `${reprojectToWgs84Sql(rawGeom, sourceCrs)} AS geom ` +\n    `FROM ${reader}`\n  );\n}\n\n/**\n * SQL creating the ingest table from a reader with a detected geometry column,\n * reprojecting to WGS84 when `sourceCrs` names a non-WGS84 CRS.\n *\n * @param tableName - The table to create\n * @param reader - Reader expression from {@link readerFor}\n * @param geometry - Detected geometry column and encoding\n * @param sourceCrs - Source CRS to reproject from (`AUTHORITY:CODE` or WKT), or\n *   null to leave the geometry in its source coordinates\n * @returns The statement text\n */\nexport function createTableFromGeometrySql(\n  tableName: string,\n  reader: string,\n  geometry: DetectedGeometryColumn,\n  sourceCrs: string | null = null,\n): string {\n  return createRelationFromGeometrySql('TABLE', tableName, reader, geometry, sourceCrs);\n}\n\n/**\n * SQL creating the ingest table from a CSV with a WKT geometry column.\n *\n * @param tableName - The table to create\n * @param reader - Reader expression\n * @param wktColumn - Name of the WKT column\n * @returns The statement text\n */\nexport function createTableFromWktSql(\n  tableName: string,\n  reader: string,\n  wktColumn: string,\n  sourceCrs: string | null = null,\n): string {\n  const geom = reprojectToWgs84Sql(`ST_GeomFromText(${quoteIdent(wktColumn)})`, sourceCrs);\n  return (\n    `CREATE OR REPLACE TABLE ${quoteIdent(tableName)} AS ` +\n    `SELECT * EXCLUDE (${quoteIdent(wktColumn)}), ` +\n    `${geom} AS geom FROM ${reader}`\n  );\n}\n\n/**\n * SQL creating the ingest table from a CSV with longitude/latitude\n * columns.\n *\n * @param tableName - The table to create\n * @param reader - Reader expression\n * @param lonColumn - Longitude column name\n * @param latColumn - Latitude column name\n * @returns The statement text\n */\nexport function createTableFromLonLatSql(\n  tableName: string,\n  reader: string,\n  lonColumn: string,\n  latColumn: string,\n  sourceCrs: string | null = null,\n): string {\n  const geom = reprojectToWgs84Sql(\n    `ST_Point(${quoteIdent(lonColumn)}, ${quoteIdent(latColumn)})`,\n    sourceCrs,\n  );\n  return (\n    `CREATE OR REPLACE TABLE ${quoteIdent(tableName)} AS ` +\n    `SELECT *, ${geom} AS geom ` +\n    `FROM ${reader}`\n  );\n}\n\n/**\n * SQL creating a streaming view over a reader instead of materializing\n * a table, normalizing the geometry column to `geom`. Used for\n * GeoParquet streaming ingest: queries hit the file in place (with\n * HTTP range reads for remote files).\n *\n * @param tableName - The view to create\n * @param reader - Reader expression from {@link readerFor}\n * @param geometryColumn - Name of the source geometry column\n * @returns The statement text\n */\nexport function createViewSql(\n  tableName: string,\n  reader: string,\n  geometryColumn: string,\n): string {\n  const rename =\n    geometryColumn === 'geom' ? '' : ` RENAME (${quoteIdent(geometryColumn)} AS geom)`;\n  return `CREATE OR REPLACE VIEW ${quoteIdent(tableName)} AS SELECT *${rename} FROM ${reader}`;\n}\n\n/**\n * SQL creating a streaming view from a reader with a detected geometry column.\n *\n * @param tableName - The view to create\n * @param reader - Reader expression from {@link readerFor}\n * @param geometry - Detected geometry column and encoding\n * @returns The statement text\n */\nexport function createViewFromGeometrySql(\n  tableName: string,\n  reader: string,\n  geometry: DetectedGeometryColumn,\n  sourceCrs: string | null = null,\n): string {\n  return createRelationFromGeometrySql('VIEW', tableName, reader, geometry, sourceCrs);\n}\n\n/**\n * Recognizes a GeoParquet bbox covering column: a STRUCT with\n * xmin/ymin/xmax/ymax fields named `bbox` or ending in `_bbox`\n * (e.g. `geometry_bbox`, `geom_bbox`).\n *\n * @param name - Column name\n * @param type - Column type string from DESCRIBE\n * @returns True when the column is a bbox covering column\n */\nexport function isBboxCoveringColumn(name: string, type: string): boolean {\n  const lower = name.toLowerCase();\n  if (lower !== 'bbox' && !lower.endsWith('_bbox')) return false;\n  const upper = type.toUpperCase();\n  return (\n    upper.startsWith('STRUCT') &&\n    /\\bXMIN\\b/.test(upper) &&\n    /\\bYMIN\\b/.test(upper) &&\n    /\\bXMAX\\b/.test(upper) &&\n    /\\bYMAX\\b/.test(upper)\n  );\n}\n\n/**\n * SQL computing feature count and extent from a bbox covering column,\n * avoiding a full geometry scan on streamed sources.\n *\n * @param tableName - The table or view to summarize\n * @param bboxColumn - The bbox covering column name\n * @returns The query text\n */\nexport function bboxSummaryQuery(tableName: string, bboxColumn: string): string {\n  const table = quoteIdent(tableName);\n  const bbox = quoteIdent(bboxColumn);\n  return (\n    `SELECT count(*)::DOUBLE AS feature_count, ` +\n    `min(${bbox}.xmin)::DOUBLE AS xmin, min(${bbox}.ymin)::DOUBLE AS ymin, ` +\n    `max(${bbox}.xmax)::DOUBLE AS xmax, max(${bbox}.ymax)::DOUBLE AS ymax ` +\n    `FROM ${table}`\n  );\n}\n\n/**\n * SQL sampling the distinct geometry types of a table or view without\n * scanning every row (streamed sources can be large).\n *\n * @param tableName - The table or view to inspect\n * @param sampleSize - Number of rows to sample\n * @returns The query text\n */\nexport function sampledGeometryTypesQuery(tableName: string, sampleSize = 100): string {\n  return (\n    `SELECT DISTINCT CAST(ST_GeometryType(geom) AS VARCHAR) AS geometry_type ` +\n    `FROM (SELECT geom FROM ${quoteIdent(tableName)} WHERE geom IS NOT NULL LIMIT ${sampleSize})`\n  );\n}\n\n/**\n * SQL generating an MVT tile from a streamed (EPSG:4326) source.\n *\n * The geometry is transformed per tile; when a bbox covering column is\n * present its predicate is pushed into parquet row-group statistics so\n * only intersecting row groups are read.\n *\n * @param tableName - The streaming view\n * @param layerName - MVT layer name (matches the map source-layer)\n * @param z - Tile zoom\n * @param x - Tile column\n * @param y - Tile row\n * @param bbox4326 - Tile bounds in EPSG:4326 [west, south, east, north]\n * @param propertyColumns - Non-geometry columns to encode as properties\n * @param bboxColumn - Optional bbox covering column for pushdown\n * @returns The query text\n */\nexport function mvtTileStreamQuery(\n  tableName: string,\n  layerName: string,\n  z: number,\n  x: number,\n  y: number,\n  bbox4326: [number, number, number, number],\n  propertyColumns: string[],\n  bboxColumn?: string,\n): string {\n  const table = quoteIdent(tableName);\n  const [west, south, east, north] = bbox4326;\n  const env3857 = `ST_TileEnvelope(${z}, ${x}, ${y})`;\n  const env4326 = `ST_MakeEnvelope(${west}, ${south}, ${east}, ${north})`;\n  const props = propertyColumns\n    .map((c) => `${quoteLiteral(c)}: TRY_CAST(${quoteIdent(c)} AS VARCHAR)`)\n    .join(', ');\n  const geometry =\n    `ST_AsMVTGeom(ST_Transform(geom, 'EPSG:4326', 'EPSG:3857', always_xy := true), ` +\n    `ST_Extent(${env3857}))`;\n  const struct = `{'geometry': ${geometry}${props ? `, ${props}` : ''}}`;\n  const bboxFilter = bboxColumn\n    ? `${quoteIdent(bboxColumn)}.xmin <= ${east} AND ${quoteIdent(bboxColumn)}.xmax >= ${west} ` +\n      `AND ${quoteIdent(bboxColumn)}.ymin <= ${north} AND ${quoteIdent(bboxColumn)}.ymax >= ${south} AND `\n    : '';\n  return (\n    `SELECT ST_AsMVT(${struct}, ${quoteLiteral(layerName)}) AS tile FROM (` +\n    `SELECT * FROM ${table} ` +\n    `WHERE ${bboxFilter}geom IS NOT NULL AND ST_Intersects(geom, ${env4326}) ` +\n    `LIMIT ${TILE_FEATURE_LIMIT})`\n  );\n}\n\n/**\n * SQL computing feature count and extent of a table.\n *\n * @param tableName - The table to summarize\n * @returns The query text\n */\nexport function summaryQuery(tableName: string): string {\n  const table = quoteIdent(tableName);\n  return (\n    `SELECT count(*)::DOUBLE AS feature_count, ` +\n    `ST_XMin(ST_Extent_Agg(geom)) AS xmin, ST_YMin(ST_Extent_Agg(geom)) AS ymin, ` +\n    `ST_XMax(ST_Extent_Agg(geom)) AS xmax, ST_YMax(ST_Extent_Agg(geom)) AS ymax ` +\n    `FROM ${table} WHERE geom IS NOT NULL`\n  );\n}\n\n/**\n * SQL listing the distinct geometry types in a table.\n *\n * @param tableName - The table to inspect\n * @returns The query text\n */\nexport function geometryTypesQuery(tableName: string): string {\n  return (\n    `SELECT DISTINCT CAST(ST_GeometryType(geom) AS VARCHAR) AS geometry_type ` +\n    `FROM ${quoteIdent(tableName)} WHERE geom IS NOT NULL LIMIT 10`\n  );\n}\n\n/**\n * SQL exporting a table as GeoJSON geometry strings plus properties.\n *\n * @param tableName - The table to export\n * @param propertyColumns - Non-geometry columns to include\n * @returns The query text\n */\nexport function exportGeoJSONQuery(tableName: string, propertyColumns: string[]): string {\n  const props = propertyColumns.map((c) => quoteIdent(c)).join(', ');\n  const selectProps = props ? `, ${props}` : '';\n  return (\n    `SELECT ST_AsGeoJSON(geom) AS __geojson${selectProps} ` +\n    `FROM ${quoteIdent(tableName)} WHERE geom IS NOT NULL`\n  );\n}\n\n/**\n * SQL reading the non-null values of one attribute column.\n *\n * @param tableName - Source table\n * @param property - Attribute column\n * @returns The query text\n */\nexport function propertyValuesQuery(tableName: string, property: string): string {\n  const column = quoteIdent(property);\n  return `SELECT ${column} AS __value FROM ${quoteIdent(tableName)} WHERE ${column} IS NOT NULL`;\n}\n\n/**\n * SQL statements preparing a table for tile generation: a Web Mercator\n * geometry column and an R-Tree index.\n *\n * @param tableName - The table to prepare\n * @returns Statements to run in order; the index statement may fail on\n *   builds without R-Tree support and should be guarded\n */\nexport function prepareTilesSql(tableName: string): { transform: string[]; index: string } {\n  const table = quoteIdent(tableName);\n  const indexName = quoteIdent(`idx_${tableName}_3857`);\n  return {\n    transform: [\n      `ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS geom_3857 GEOMETRY`,\n      `UPDATE ${table} SET geom_3857 = ST_Transform(geom, 'EPSG:4326', 'EPSG:3857', always_xy := true)`,\n    ],\n    index: `CREATE INDEX IF NOT EXISTS ${indexName} ON ${table} USING RTREE (geom_3857)`,\n  };\n}\n\n/**\n * SQL generating an MVT tile for a z/x/y request using ST_AsMVT.\n *\n * Properties are cast to VARCHAR for MVT encoding robustness.\n *\n * @param tableName - The prepared source table\n * @param layerName - MVT layer name (matches the map source-layer)\n * @param z - Tile zoom\n * @param x - Tile column\n * @param y - Tile row\n * @param propertyColumns - Non-geometry columns to encode as properties\n * @returns The query text\n */\nexport function mvtTileQuery(\n  tableName: string,\n  layerName: string,\n  z: number,\n  x: number,\n  y: number,\n  propertyColumns: string[],\n): string {\n  const table = quoteIdent(tableName);\n  const env = `ST_TileEnvelope(${z}, ${x}, ${y})`;\n  const props = propertyColumns\n    .map((c) => `${quoteLiteral(c)}: TRY_CAST(${quoteIdent(c)} AS VARCHAR)`)\n    .join(', ');\n  const struct = `{'geometry': ST_AsMVTGeom(geom_3857, ST_Extent(${env}))${props ? `, ${props}` : ''}}`;\n  return (\n    `SELECT ST_AsMVT(${struct}, ${quoteLiteral(layerName)}) AS tile FROM (` +\n    `SELECT * FROM ${table} ` +\n    `WHERE geom_3857 IS NOT NULL AND ST_Intersects(geom_3857, ${env}) ` +\n    `LIMIT ${TILE_FEATURE_LIMIT})`\n  );\n}\n\n/**\n * SQL selecting tile-intersecting features as GeoJSON for the JS MVT\n * fallback encoder (used when ST_AsMVT is unavailable).\n *\n * @param tableName - The source table\n * @param bbox - Tile bounds in EPSG:4326 [west, south, east, north]\n * @param propertyColumns - Non-geometry columns to include\n * @returns The query text\n */\nexport function tileFeaturesQuery(\n  tableName: string,\n  bbox: [number, number, number, number],\n  propertyColumns: string[],\n): string {\n  const table = quoteIdent(tableName);\n  const envelope = `ST_MakeEnvelope(${bbox[0]}, ${bbox[1]}, ${bbox[2]}, ${bbox[3]})`;\n  const props = propertyColumns.map((c) => quoteIdent(c)).join(', ');\n  const selectProps = props ? `, ${props}` : '';\n  return (\n    `SELECT ST_AsGeoJSON(geom) AS __geojson${selectProps} FROM ${table} ` +\n    `WHERE geom IS NOT NULL AND ST_Intersects(geom, ${envelope}) ` +\n    `LIMIT ${TILE_FEATURE_LIMIT}`\n  );\n}\n\n/**\n * SQL listing the named layers inside a multi-layer container\n * (GeoPackage tables, KML folders, ...) via ST_Read_Meta.\n *\n * @param path - Registered file name or URL\n * @returns The query text\n */\nexport function layersMetaQuery(path: string): string {\n  return (\n    `SELECT layer.name AS name FROM ` +\n    `(SELECT unnest(layers) AS layer FROM ST_Read_Meta(${quoteLiteral(path)}))`\n  );\n}\n\n/**\n * An `ST_Read` reader that keeps geometry as raw WKB (a `wkb_geometry` BLOB)\n * instead of decoding it into DuckDB's GEOMETRY type. Used as a fallback for\n * surface geometries (TIN / PolyhedralSurface) whose WKB DuckDB Spatial cannot\n * parse, so the raw bytes can be decoded in JS instead.\n *\n * @param path - Registered file name or URL\n * @param sourceLayer - Optional OGR layer name for a multi-layer source\n * @returns The reader expression\n */\nexport function keepWkbReaderFor(path: string, sourceLayer?: string): string {\n  const layerArg = sourceLayer ? `, layer = ${quoteLiteral(sourceLayer)}` : '';\n  return `ST_Read(${quoteLiteral(path)}${layerArg}, keep_wkb = true)`;\n}\n\n/**\n * SQL reading the first layer's first geometry field CRS from `ST_Read_Meta`,\n * used to reproject a surface-geometry fallback layer to WGS84. `wkt` is the\n * fallback when GDAL could not resolve an EPSG code (e.g. a custom ESRI `.prj`);\n * `ST_Transform` accepts a WKT string source just as it does `AUTHORITY:CODE`.\n *\n * @param path - Registered file name or URL\n * @returns The query text\n */\nexport function sourceCrsMetaQuery(path: string): string {\n  return (\n    `SELECT ` +\n    `layers[1].geometry_fields[1].crs.auth_name AS auth_name, ` +\n    `layers[1].geometry_fields[1].crs.auth_code AS auth_code, ` +\n    `layers[1].geometry_fields[1].crs.wkt AS wkt ` +\n    `FROM ST_Read_Meta(${quoteLiteral(path)})`\n  );\n}\n\n/**\n * The Parquet file-metadata key the GeoParquet specification writes its column\n * metadata (including the CRS) to.\n */\nexport const GEOPARQUET_METADATA_KEY = 'geo';\n\n/** The column {@link geoParquetCrsQuery} returns the metadata document in. */\nexport const GEOPARQUET_METADATA_COLUMN = 'geo_metadata';\n\n/**\n * SQL reading a Parquet file's `geo` metadata document as text, the only place\n * a GeoParquet source declares its CRS (`read_parquet` reports nothing about it\n * the way `ST_Read_Meta` does for the GDAL formats). Returns no rows for a\n * plain, non-spatial Parquet.\n *\n * The key is matched as a BLOB via `encode` rather than by decoding every key,\n * so a file carrying a non-UTF-8 metadata key cannot fail the whole read; only\n * the matched row's value is decoded.\n *\n * @param path - Registered file name or URL\n * @returns The query text\n */\nexport function geoParquetCrsQuery(path: string): string {\n  return (\n    `SELECT decode(value) AS ${GEOPARQUET_METADATA_COLUMN} ` +\n    `FROM parquet_kv_metadata(${quoteLiteral(path)}) ` +\n    `WHERE key = encode(${quoteLiteral(GEOPARQUET_METADATA_KEY)})`\n  );\n}\n\n/**\n * SQL probing whether the loaded spatial build supports ST_AsMVT.\n *\n * @returns The probe query text\n */\nexport function mvtProbeQuery(): string {\n  return (\n    `SELECT ST_AsMVT({'geometry': ST_AsMVTGeom(ST_Point(0, 0), ` +\n    `ST_Extent(ST_TileEnvelope(0, 0, 0)))}, 'probe') AS tile`\n  );\n}\n\n/**\n * Column names recognized as WKT geometry in CSV files.\n */\nexport const WKT_COLUMN_NAMES = ['geometry', 'wkt', 'geom', 'the_geom', 'wkb_geometry'];\n\n/**\n * Column name pairs recognized as longitude/latitude in CSV files.\n */\nexport const LON_LAT_COLUMN_PAIRS: Array<[string, string]> = [\n  ['longitude', 'latitude'],\n  ['lon', 'lat'],\n  ['lng', 'lat'],\n  ['x', 'y'],\n];\n","import { mvtProbeQuery } from './sql';\n\n/**\n * Pinned duckdb-wasm version.\n *\n * IMPORTANT: a higher duckdb-wasm version does NOT guarantee a newer\n * DuckDB core. v1.31.0 ships DuckDB core 1.4.0, which is the first core\n * with ST_AsMVT/ST_AsMVTGeom; some later wasm releases regressed to\n * core 1.3.x. Verify with the runtime probe before changing this pin.\n */\nexport const DUCKDB_WASM_VERSION = '1.31.0';\n\n/**\n * jsDelivr base URL for the pinned duckdb-wasm package. Used as the default\n * when no custom base is configured.\n */\nexport const DUCKDB_CDN_BASE = `https://cdn.jsdelivr.net/npm/@duckdb/duckdb-wasm@${DUCKDB_WASM_VERSION}`;\n\n/**\n * Rewrites the jsDelivr URLs returned by `getJsDelivrBundles()` to a custom\n * base so the `.wasm` and worker assets load from a self-hosted (or mirrored)\n * location instead of the CDN.\n *\n * The base must mirror jsDelivr's layout for duckdb-wasm\n * {@link DUCKDB_WASM_VERSION}: an `/+esm` ES-module bundle plus the `/dist/*`\n * wasm and worker files. A trailing slash on the base is ignored.\n *\n * @param bundles - Bundle map from duckdb-wasm's `getJsDelivrBundles()`.\n * @param base - Target base URL (e.g. `/vendor/duckdb-wasm-1.31.0`).\n * @returns A new bundle map with rebased URLs (the default base is a no-op).\n */\nexport function rebaseDuckDBBundles<T>(bundles: T, base: string): T {\n  const normalized = base.replace(/\\/+$/, '');\n  if (normalized === DUCKDB_CDN_BASE) return bundles;\n  const rebased = JSON.stringify(bundles).split(DUCKDB_CDN_BASE).join(normalized);\n  return JSON.parse(rebased) as T;\n}\n\n/**\n * Minimal structural types for the duckdb-wasm API surface we use.\n * Full types are not imported because the package is loaded from a CDN\n * at runtime and is not a dependency.\n */\nexport interface DuckDBConnection {\n  query(text: string): Promise<ArrowTable>;\n  close(): Promise<void>;\n}\n\nexport interface ArrowTable {\n  numRows: number;\n  toArray(): Array<Record<string, unknown>>;\n}\n\nexport interface DuckDBDatabase {\n  connect(): Promise<DuckDBConnection>;\n  registerFileBuffer(name: string, buffer: Uint8Array): Promise<void>;\n  registerFileURL(name: string, url: string, protocol: number, directIO: boolean): Promise<void>;\n  dropFile(name: string): Promise<void>;\n  terminate(): Promise<void>;\n}\n\n/**\n * A loaded DuckDB instance with its primary connection.\n */\nexport interface LoadedDuckDB {\n  db: DuckDBDatabase;\n  conn: DuckDBConnection;\n  /** Whether the spatial build supports native ST_AsMVT tiles */\n  supportsMVT: boolean;\n  /** DuckDB core version string */\n  version: string;\n  /** The HTTP value of duckdb-wasm's DuckDBDataProtocol enum */\n  httpProtocol: number;\n}\n\n/**\n * Builds the SQL that loads the spatial extension.\n *\n * With no path, the extension is installed from DuckDB's remote repository\n * (`INSTALL spatial; LOAD spatial;`). With a path, the remote INSTALL is\n * skipped in favour of `LOAD '<path>'` so the load works offline; the path is\n * normalized (Windows separators) and single-quote-escaped for the literal.\n *\n * @param spatialExtensionPath - Optional path/URL to a prebuilt extension\n * @returns The SQL statement(s) to run on a fresh connection\n */\nexport function spatialExtensionLoadSql(spatialExtensionPath?: string): string {\n  if (!spatialExtensionPath) return 'INSTALL spatial; LOAD spatial;';\n  const normalized = spatialExtensionPath.replace(/\\\\/g, '/').replace(/'/g, \"''\");\n  return `LOAD '${normalized}'`;\n}\n\n/**\n * Imports a module by URL at runtime without bundler interference.\n * Indirection through Function keeps Vite/webpack/rollup from trying to\n * resolve or rewrite the CDN import.\n */\nconst dynamicImport = new Function('url', 'return import(url)') as (\n  url: string,\n) => Promise<Record<string, unknown>>;\n\n/**\n * Loads a remote ES module from a URL.\n *\n * Exported for reuse by the MVT JS fallback loader.\n *\n * @param url - Module URL\n * @returns The module namespace object\n */\nexport function importFromCdn(url: string): Promise<Record<string, unknown>> {\n  return dynamicImport(url);\n}\n\nconst cdnScriptPromises = new Map<string, Promise<void>>();\n\n/**\n * Loads a classic (non-module) script from a URL via a `<script>` tag, once per\n * URL. Used for UMD CDN bundles that publish a global rather than an ES module\n * (e.g. sql.js, whose `/+esm` build cannot be bundled because it imports `fs`).\n *\n * @param url - Script URL\n * @returns Resolves when the script has loaded\n */\nexport function loadScriptFromCdn(url: string): Promise<void> {\n  let promise = cdnScriptPromises.get(url);\n  if (!promise) {\n    promise = new Promise<void>((resolve, reject) => {\n      const script = document.createElement('script');\n      script.src = url;\n      script.async = true;\n      script.onload = () => resolve();\n      script.onerror = () => {\n        cdnScriptPromises.delete(url);\n        reject(new Error(`Failed to load script: ${url}`));\n      };\n      document.head.appendChild(script);\n    });\n    cdnScriptPromises.set(url, promise);\n  }\n  return promise;\n}\n\n/**\n * Loads DuckDB-WASM from jsDelivr, instantiates it in a worker, loads\n * the spatial extension, and probes MVT support.\n *\n * @param onProgress - Optional progress message callback\n * @param baseUrl - Optional base URL to load duckdb-wasm from instead of\n *   jsDelivr. Must mirror jsDelivr's layout (`/+esm` plus `/dist/*`) for the\n *   pinned {@link DUCKDB_WASM_VERSION}; lets a host self-host the assets and\n *   avoid the CDN (and the CSP allowance it requires).\n * @param spatialExtensionPath - Optional path/URL to a prebuilt spatial\n *   extension. When set, the spatial extension is loaded with `LOAD '<path>'`\n *   and the remote `INSTALL spatial` step is skipped, so the load does not hang\n *   in sandboxed or firewalled environments where DuckDB's extension repository\n *   is unreachable.\n * @returns The loaded database, connection, and capabilities\n */\nexport async function loadDuckDB(\n  onProgress?: (message: string) => void,\n  baseUrl?: string,\n  spatialExtensionPath?: string,\n): Promise<LoadedDuckDB> {\n  onProgress?.('Loading DuckDB-WASM...');\n  const base = (baseUrl ?? DUCKDB_CDN_BASE).replace(/\\/+$/, '');\n  /* eslint-disable @typescript-eslint/no-explicit-any */\n  const duckdb: any = await dynamicImport(`${base}/+esm`);\n\n  const bundles = rebaseDuckDBBundles(duckdb.getJsDelivrBundles(), base);\n  const bundle = await duckdb.selectBundle(bundles);\n\n  const workerUrl = URL.createObjectURL(\n    new Blob([`importScripts(\"${bundle.mainWorker}\");`], { type: 'text/javascript' }),\n  );\n  const worker = new Worker(workerUrl);\n  const logger = new duckdb.VoidLogger();\n  const db: any = new duckdb.AsyncDuckDB(logger, worker);\n  try {\n    await db.instantiate(bundle.mainModule, bundle.pthreadWorker);\n  } finally {\n    URL.revokeObjectURL(workerUrl);\n  }\n\n  onProgress?.('Loading spatial extension...');\n  const conn: DuckDBConnection = await db.connect();\n  await conn.query(spatialExtensionLoadSql(spatialExtensionPath));\n\n  const versionRows = (await conn.query('SELECT version() AS v')).toArray();\n  const version = String(versionRows[0]?.v ?? 'unknown');\n\n  let supportsMVT = false;\n  try {\n    await conn.query(mvtProbeQuery());\n    supportsMVT = true;\n  } catch {\n    // Older core without ST_AsMVT; the JS fallback encoder is used instead.\n  }\n\n  const httpProtocol = Number(duckdb.DuckDBDataProtocol?.HTTP ?? 4);\n  /* eslint-enable @typescript-eslint/no-explicit-any */\n\n  return { db: db as DuckDBDatabase, conn, supportsMVT, version, httpProtocol };\n}\n","/**\n * Repairs GeoPackages that lack the `gpkg_ogr_contents` feature-count table so\n * DuckDB-WASM's `ST_Read` can open them without crashing.\n *\n * When a GeoPackage has no `gpkg_ogr_contents`, GDAL's GeoPackage driver cannot\n * get a cheap feature count and takes its multithreaded async Arrow read path,\n * which calls `std::thread`/`pthread_create`. The single-threaded DuckDB-WASM\n * build loaded in a browser (no cross-origin isolation, so no pthread support)\n * then fails the read with:\n *\n *   \"thread constructor failed: Resource temporarily unavailable\"\n *\n * Files written by ogr2ogr/GDAL include `gpkg_ogr_contents` and load fine; files\n * written by QGIS often omit it and crash. Injecting the table with a cached\n * count keeps GDAL on the fast, single-threaded path. See\n * https://github.com/opengeos/GeoLibre/issues/258.\n *\n * sql.js is loaded from a CDN on demand (only when a GeoPackage is added),\n * mirroring how duckdb-wasm is loaded, so it is not a bundled dependency.\n */\n\nimport { loadScriptFromCdn } from \"./duckdbLoader\";\n\n/** Pinned sql.js version loaded from the CDN. */\nexport const SQLJS_VERSION = \"1.13.0\";\n\n/** jsDelivr base URL for the pinned sql.js package. */\nexport const SQLJS_CDN_BASE = `https://cdn.jsdelivr.net/npm/sql.js@${SQLJS_VERSION}`;\n\nconst SQLITE_MAGIC = \"SQLite format 3\\0\";\n\n/** Minimal structural types for the sql.js API surface we use. */\nexport interface SqlJsQueryResult {\n  columns: string[];\n  values: Array<Array<string | number | Uint8Array | null>>;\n}\n\nexport interface SqlJsDatabase {\n  run(sql: string, params?: Record<string, unknown>): void;\n  exec(sql: string, params?: Record<string, unknown>): SqlJsQueryResult[];\n  export(): Uint8Array;\n  close(): void;\n}\n\nexport interface SqlJsStatic {\n  Database: new (data?: Uint8Array) => SqlJsDatabase;\n}\n\ntype InitSqlJs = (config?: {\n  locateFile?: (file: string) => string;\n}) => Promise<SqlJsStatic>;\n\n/** A SQLite/GeoPackage file begins with the 16-byte \"SQLite format 3\\0\" magic. */\nexport function looksLikeSqlite(bytes: Uint8Array): boolean {\n  if (bytes.length < SQLITE_MAGIC.length) return false;\n  for (let i = 0; i < SQLITE_MAGIC.length; i += 1) {\n    if (bytes[i] !== SQLITE_MAGIC.charCodeAt(i)) return false;\n  }\n  return true;\n}\n\nexport function quoteIdentifier(value: string): string {\n  return `\"${value.replace(/\"/g, '\"\"')}\"`;\n}\n\nexport function tableExists(db: SqlJsDatabase, name: string): boolean {\n  const result = db.exec(\n    \"SELECT 1 FROM sqlite_master WHERE type='table' AND name=:name\",\n    { \":name\": name },\n  );\n  return result.length > 0 && result[0].values.length > 0;\n}\n\n/**\n * Synchronous core of {@link ensureGpkgFeatureCount}, separated so it can be\n * unit-tested with an already-initialised sql.js factory. Returns the original\n * buffer unchanged when the file is not a GeoPackage or already has a count for\n * every feature table; otherwise returns a patched buffer.\n *\n * @param SQL - An initialised sql.js factory.\n * @param bytes - The GeoPackage file bytes.\n * @returns The original or patched bytes.\n */\nexport function ensureGpkgFeatureCountSync(\n  SQL: SqlJsStatic,\n  bytes: Uint8Array,\n): Uint8Array {\n  const db = new SQL.Database(bytes);\n  try {\n    // gpkg_contents is mandatory in the spec; only touch real GeoPackages.\n    if (!tableExists(db, \"gpkg_contents\")) return bytes;\n\n    const featureTablesResult = db.exec(\n      \"SELECT table_name FROM gpkg_contents WHERE data_type='features'\",\n    );\n    if (\n      featureTablesResult.length === 0 ||\n      featureTablesResult[0].values.length === 0\n    ) {\n      return bytes;\n    }\n    const featureTables = featureTablesResult[0].values\n      .map((row) => row[0])\n      .filter((name): name is string => typeof name === \"string\");\n\n    const hasOgrContents = tableExists(db, \"gpkg_ogr_contents\");\n    const existingCounts = new Set<string>();\n    if (hasOgrContents) {\n      const existing = db.exec(\"SELECT table_name FROM gpkg_ogr_contents\");\n      for (const row of existing[0]?.values ?? []) {\n        if (typeof row[0] === \"string\") existingCounts.add(row[0]);\n      }\n    }\n\n    const missing = featureTables.filter((name) => !existingCounts.has(name));\n    if (missing.length === 0) return bytes;\n\n    if (!hasOgrContents) {\n      db.run(\n        \"CREATE TABLE gpkg_ogr_contents (\" +\n          \"table_name TEXT NOT NULL PRIMARY KEY, \" +\n          \"feature_count INTEGER DEFAULT NULL)\",\n      );\n    }\n\n    for (const tableName of missing) {\n      const countResult = db.exec(\n        `SELECT count(*) FROM ${quoteIdentifier(tableName)}`,\n      );\n      const count = countResult[0]?.values[0]?.[0] ?? 0;\n      db.run(\n        \"INSERT INTO gpkg_ogr_contents (table_name, feature_count) VALUES (:name, :count)\",\n        { \":name\": tableName, \":count\": count },\n      );\n    }\n\n    return db.export();\n  } finally {\n    db.close();\n  }\n}\n\nlet sqlJsPromise: Promise<SqlJsStatic> | null = null;\n\n/**\n * Loads sql.js from the CDN (or a self-hosted mirror) and initialises it.\n *\n * @param baseUrl - Optional base URL mirroring jsDelivr's layout for the pinned\n *   {@link SQLJS_VERSION} (a `/dist/sql-wasm.js` UMD script plus the matching\n *   `/dist/sql-wasm.wasm`). Defaults to jsDelivr when unset.\n */\nexport async function loadSqlJs(baseUrl?: string): Promise<SqlJsStatic> {\n  if (!sqlJsPromise) {\n    const base = (baseUrl ?? SQLJS_CDN_BASE).replace(/\\/+$/, \"\");\n    sqlJsPromise = (async () => {\n      await loadScriptFromCdn(`${base}/dist/sql-wasm.js`);\n      const initSqlJs = (globalThis as { initSqlJs?: InitSqlJs }).initSqlJs;\n      if (!initSqlJs) {\n        throw new Error(\"sql.js failed to expose a global initSqlJs\");\n      }\n      return initSqlJs({ locateFile: (file) => `${base}/dist/${file}` });\n    })();\n    sqlJsPromise.catch(() => {\n      // Allow a retry on the next call when the CDN was unreachable.\n      sqlJsPromise = null;\n    });\n  }\n  return sqlJsPromise;\n}\n\n/**\n * Returns a GeoPackage buffer guaranteed to carry `gpkg_ogr_contents` for every\n * feature table, patching it in-memory when needed. Non-GeoPackage input and\n * already-complete files are returned untouched. Best-effort: if sql.js fails to\n * load or the file cannot be parsed, the original buffer is returned so the\n * normal `ST_Read` error path still applies.\n *\n * @param bytes - The GeoPackage file bytes.\n * @param baseUrl - Optional sql.js base URL; see {@link loadSqlJs}.\n * @returns The original or patched bytes.\n */\nexport async function ensureGpkgFeatureCount(\n  bytes: Uint8Array,\n  baseUrl?: string,\n): Promise<Uint8Array> {\n  if (!looksLikeSqlite(bytes)) return bytes;\n  try {\n    const SQL = await loadSqlJs(baseUrl);\n    return ensureGpkgFeatureCountSync(SQL, bytes);\n  } catch (error) {\n    console.warn(\n      \"[maplibre-gl-vector] Could not ensure gpkg_ogr_contents; reading file as-is.\",\n      error,\n    );\n    return bytes;\n  }\n}\n","import type { Feature, FeatureCollection, Geometry, Position } from \"geojson\";\nimport {\n  loadSqlJs,\n  looksLikeSqlite,\n  quoteIdentifier,\n  tableExists,\n  type SqlJsDatabase,\n  type SqlJsStatic,\n} from \"./gpkgOgrContents\";\n\n/**\n * Reads GeoPackages with sql.js (SQLite/WASM) instead of DuckDB's `ST_Read`.\n *\n * GDAL's GeoPackage driver opens the file through the SQLite VFS and, on the\n * single-threaded DuckDB-WASM build a browser loads (no cross-origin isolation,\n * so no pthread support), the read either crashes with\n * \"thread constructor failed: Resource temporarily unavailable\" or hangs\n * indefinitely probing for `-journal`/`-wal` sidecar files that the registered\n * in-memory file has no real directory for. Repairing `gpkg_ogr_contents` (see\n * `gpkgOgrContents.ts`) keeps GDAL on its single-threaded path for the\n * feature-count crash, but does not fix the hang, and no DuckDB-reachable GDAL\n * config disables it. Reading the SQLite tables directly with sql.js sidesteps\n * GDAL entirely: a GeoPackage geometry blob is a thin \"GP\" header over standard\n * WKB, and {@link decodeWkb} turns that WKB into GeoJSON. The caller then loads\n * the resulting GeoJSON through DuckDB (whose GeoJSON reader is unaffected) and\n * reprojects with `ST_Transform` when the layer is not already WGS84.\n *\n * See https://github.com/opengeos/GeoLibre/issues/1013 and #258.\n */\n\n/** A selected feature layer plus the metadata needed to read its rows. */\ninterface GeoPackageLayer {\n  table: string;\n  geometryColumn: string;\n  srsId: number | null;\n  /** The INTEGER PRIMARY KEY column, excluded from feature properties. */\n  idColumn: string | null;\n}\n\nexport interface GeoPackageReadResult {\n  featureCollection: FeatureCollection<Geometry | null>;\n  /**\n   * The CRS the geometries are stored in, as an `EPSG:<code>` string or a raw\n   * WKT definition, or null when they are already WGS84 lon/lat (or the CRS is\n   * undefined). The caller reprojects when set.\n   */\n  sourceCrs: string | null;\n}\n\n// Envelope byte sizes by GeoPackage envelope indicator: 0=none, 1=XY, 2=XYZ,\n// 3=XYM, 4=XYZM. Indicators 5-7 are reserved/invalid (OGC 12-128r18, Table 1).\nconst ENVELOPE_BYTES = [0, 32, 48, 48, 64];\n\n/**\n * Strips the GeoPackage geometry-blob header, returning the standard WKB inside.\n *\n * The header is the \"GP\" magic, a version byte, a flags byte, a 4-byte srs_id,\n * and an optional envelope whose size is encoded in flag bits 1-3. A blob that\n * is already bare WKB (first byte a 0x00/0x01 byte-order marker) is returned\n * unchanged so non-conformant producers still read. A blob that claims the \"GP\"\n * magic but is truncated or carries a reserved envelope indicator throws, so a\n * malformed geometry surfaces as an explicit error instead of decoding from the\n * wrong offset into a silently wrong (or null) geometry.\n *\n * @param blob - The raw GeoPackage geometry blob.\n * @returns The standalone WKB bytes.\n */\nexport function stripGeoPackageHeader(blob: Uint8Array): Uint8Array {\n  // 'G','P' magic identifies a GeoPackage geometry blob; otherwise assume the\n  // value is already standalone WKB (byte-order byte 0x00 or 0x01).\n  if (blob.length < 2 || blob[0] !== 0x47 || blob[1] !== 0x50) return blob;\n  if (blob.length < 8) {\n    throw new Error(\"Invalid GeoPackage geometry blob: truncated header.\");\n  }\n  const flags = blob[3];\n  const envelopeIndicator = (flags >> 1) & 0x07;\n  if (envelopeIndicator >= ENVELOPE_BYTES.length) {\n    throw new Error(\n      `Invalid GeoPackage geometry blob: reserved envelope indicator ${envelopeIndicator}.`,\n    );\n  }\n  const headerLength = 8 + ENVELOPE_BYTES[envelopeIndicator];\n  if (blob.length < headerLength) {\n    throw new Error(\"Invalid GeoPackage geometry blob: truncated envelope.\");\n  }\n  return blob.subarray(headerLength);\n}\n\n/**\n * Whether a GeoPackage geometry blob is flagged empty (header flags bit 0x10).\n *\n * The WKB body of an empty geometry is still well-formed but represents \"no\n * geometry\" (an empty Point even carries NaN coordinates), so the flag is\n * honoured to emit a null GeoJSON geometry rather than decoding bogus\n * coordinates. A bare-WKB blob (no \"GP\" magic) has no flag and is never empty.\n *\n * @param blob - The raw GeoPackage geometry blob.\n * @returns True when the blob's empty-geometry flag is set.\n */\nexport function isGeoPackageEmptyGeometry(blob: Uint8Array): boolean {\n  return (\n    blob.length >= 4 &&\n    blob[0] === 0x47 &&\n    blob[1] === 0x50 &&\n    (blob[3] & 0x10) !== 0\n  );\n}\n\n/**\n * Decodes a standalone WKB (Well-Known Binary) buffer into a GeoJSON geometry.\n *\n * Handles mixed byte order, ISO WKB dimensionality (Z/M, where the type code is\n * offset by 1000/2000/3000) and the PostGIS EWKB Z/M/SRID high-bit flags. The M\n * ordinate is dropped; Z is kept so a `[x, y, z]` position survives. Surface\n * geometries (TIN / PolyhedralSurface / Triangle, codes 15-17) — the encoding\n * GDAL produces for ESRI MultiPatch shapefiles — have no GeoJSON equivalent, so\n * each is exposed as a MultiPolygon (or Polygon, for a lone Triangle). Throws on\n * the curved geometry types (CircularString and friends, codes 8-12) that\n * GeoJSON cannot represent.\n *\n * @param bytes - The WKB buffer (no GeoPackage header).\n * @returns The decoded GeoJSON geometry.\n */\nexport function decodeWkb(bytes: Uint8Array): Geometry {\n  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n  let offset = 0;\n\n  function readGeometry(): Geometry {\n    const little = view.getUint8(offset) === 1;\n    offset += 1;\n    const rawType = view.getUint32(offset, little);\n    offset += 4;\n\n    // PostGIS EWKB encodes Z/M/SRID in the high bits; ISO WKB encodes Z/M by\n    // offsetting the type code (1000 = Z, 2000 = M, 3000 = ZM). Support both so\n    // any standards-conformant GeoPackage geometry blob decodes.\n    const hasEwkbZ = (rawType & 0x80000000) !== 0;\n    const hasEwkbM = (rawType & 0x40000000) !== 0;\n    const hasSrid = (rawType & 0x20000000) !== 0;\n    const baseType = rawType & 0xffff;\n    const isoGroup = Math.floor((baseType % 4000) / 1000);\n    const code = baseType % 1000;\n    const hasZ = hasEwkbZ || isoGroup === 1 || isoGroup === 3;\n    const hasM = hasEwkbM || isoGroup === 2 || isoGroup === 3;\n\n    // An EWKB SRID prefix precedes the coordinates; skip it (the layer CRS is\n    // taken from the GeoPackage metadata, not the per-geometry SRID).\n    if (hasSrid) offset += 4;\n\n    const readPosition = (): Position => {\n      const x = view.getFloat64(offset, little);\n      offset += 8;\n      const y = view.getFloat64(offset, little);\n      offset += 8;\n      let z: number | undefined;\n      if (hasZ) {\n        z = view.getFloat64(offset, little);\n        offset += 8;\n      }\n      if (hasM) offset += 8; // M is not represented in GeoJSON.\n      return z === undefined ? [x, y] : [x, y, z];\n    };\n\n    const readPositions = (): Position[] => {\n      const count = view.getUint32(offset, little);\n      offset += 4;\n      const positions: Position[] = [];\n      for (let i = 0; i < count; i += 1) positions.push(readPosition());\n      return positions;\n    };\n\n    const readRings = (): Position[][] => {\n      const count = view.getUint32(offset, little);\n      offset += 4;\n      const rings: Position[][] = [];\n      for (let i = 0; i < count; i += 1) rings.push(readPositions());\n      return rings;\n    };\n\n    const readChildren = (): Geometry[] => {\n      const count = view.getUint32(offset, little);\n      offset += 4;\n      const children: Geometry[] = [];\n      for (let i = 0; i < count; i += 1) children.push(readGeometry());\n      return children;\n    };\n\n    switch (code) {\n      case 1:\n        return { type: \"Point\", coordinates: readPosition() };\n      case 2:\n        return { type: \"LineString\", coordinates: readPositions() };\n      case 3:\n        return { type: \"Polygon\", coordinates: readRings() };\n      case 4: {\n        const points = readChildren();\n        return {\n          type: \"MultiPoint\",\n          coordinates: points.map(\n            (p) => (p as { coordinates: Position }).coordinates,\n          ),\n        };\n      }\n      case 5: {\n        const lines = readChildren();\n        return {\n          type: \"MultiLineString\",\n          coordinates: lines.map(\n            (l) => (l as { coordinates: Position[] }).coordinates,\n          ),\n        };\n      }\n      case 6: {\n        const polygons = readChildren();\n        return {\n          type: \"MultiPolygon\",\n          coordinates: polygons.map(\n            (p) => (p as { coordinates: Position[][] }).coordinates,\n          ),\n        };\n      }\n      case 7:\n        return { type: \"GeometryCollection\", geometries: readChildren() };\n      case 15: {\n        // PolyhedralSurface: a set of polygon patches. GeoJSON has no surface\n        // type, so expose the patches as a MultiPolygon (each patch keeps its\n        // own header, so readChildren decodes them like MultiPolygon members).\n        const patches = readChildren();\n        return {\n          type: \"MultiPolygon\",\n          coordinates: patches.map(\n            (patch) => (patch as { coordinates: Position[][] }).coordinates,\n          ),\n        };\n      }\n      case 16: {\n        // TIN (Triangulated Irregular Network): a set of Triangle patches, the\n        // encoding GDAL emits for an ESRI MultiPatch shapefile (3D buildings).\n        // Each triangle decodes to a Polygon (case 17), so the surface becomes a\n        // MultiPolygon MapLibre can render.\n        const triangles = readChildren();\n        return {\n          type: \"MultiPolygon\",\n          coordinates: triangles.map(\n            (triangle) =>\n              (triangle as { coordinates: Position[][] }).coordinates,\n          ),\n        };\n      }\n      case 17:\n        // Triangle: a Polygon constrained to a single 4-vertex ring.\n        return { type: \"Polygon\", coordinates: readRings() };\n      default:\n        // Codes 8-12 are the curved geometries (CircularString, CompoundCurve,\n        // CurvePolygon, MultiCurve, MultiSurface) that GeoJSON cannot represent.\n        throw new Error(\n          `Unsupported WKB geometry type ${code}${\n            code >= 8 && code <= 12\n              ? \" (curved geometries are not supported)\"\n              : \"\"\n          }.`,\n        );\n    }\n  }\n\n  return readGeometry();\n}\n\n/**\n * Lists every `features` row in `gpkg_contents` that has a registered geometry\n * column, in declaration order. Mirrors GDAL's layer enumeration so a\n * multi-layer GeoPackage can be expanded one layer per row.\n */\nfunction selectLayers(db: SqlJsDatabase): GeoPackageLayer[] {\n  // Both tables are referenced by the JOIN below. gpkg_contents is mandatory in\n  // the spec, but guard it too so a malformed file returns no layers here rather\n  // than throwing an opaque sql.js error from the JOIN.\n  if (!tableExists(db, \"gpkg_geometry_columns\")) return [];\n  if (!tableExists(db, \"gpkg_contents\")) return [];\n  const result = db.exec(\n    // COLLATE NOCASE: SQLite's default BINARY collation makes the join\n    // case-sensitive, but a producer can spell the same table differently in\n    // gpkg_contents and gpkg_geometry_columns (SQLite table names are\n    // case-insensitive). gpkgOgrContents.ts handles the same mismatch.\n    `SELECT g.table_name, g.column_name, g.srs_id\n     FROM gpkg_geometry_columns g\n     JOIN gpkg_contents c ON c.table_name = g.table_name COLLATE NOCASE\n     WHERE lower(c.data_type) = 'features'\n     ORDER BY c.rowid`,\n  );\n  const rows = result[0]?.values ?? [];\n  return rows.map((row) => {\n    const table = String(row[0]);\n    return {\n      table,\n      geometryColumn: String(row[1]),\n      srsId: row[2] == null ? null : Number(row[2]),\n      idColumn: findIdColumn(db, table),\n    };\n  });\n}\n\n/** Finds a table's INTEGER PRIMARY KEY column (excluded from properties). */\nfunction findIdColumn(db: SqlJsDatabase, table: string): string | null {\n  let idColumn: string | null = null;\n  for (const info of db.exec(`PRAGMA table_info(${quoteIdentifier(table)})`)[0]\n    ?.values ?? []) {\n    // table_info columns: cid, name, type, notnull, dflt_value, pk.\n    if (info[5] === 1) idColumn = String(info[1]);\n  }\n  return idColumn;\n}\n\n/**\n * Picks the layer to read: the named layer when `sourceLayer` is given (matched\n * case-insensitively), otherwise the first feature layer. Returns null when the\n * file has no matching feature layer.\n */\nfunction selectLayer(\n  db: SqlJsDatabase,\n  sourceLayer?: string,\n): GeoPackageLayer | null {\n  const layers = selectLayers(db);\n  if (layers.length === 0) return null;\n  if (!sourceLayer) return layers[0];\n  const target = sourceLayer.toLowerCase();\n  return layers.find((layer) => layer.table.toLowerCase() === target) ?? null;\n}\n\n// EPSG codes whose horizontal axes are already WGS84 lon/lat, so reprojecting\n// to 4326 is a no-op: 4326 (2D) and 4979 (3D geographic, same lat/lon).\nconst WGS84_EPSG_CODES = new Set([4326, 4979]);\n\n/**\n * Resolves the layer's SRS to something `ST_Transform` accepts — an\n * `EPSG:<code>` string, or the row's WKT definition — or null when the\n * geometries are already WGS84 lon/lat or the CRS is undefined (srs_id 0 =\n * undefined geographic, -1 = undefined cartesian).\n *\n * EPSG-organization rows resolve to their code. Anything else falls back to the\n * stored `definition`: a GeoPackage may mint its own srs_id under an\n * organization like \"CUSTOM\" or \"NONE\" while still carrying a perfectly usable\n * WKT (a statewide wetlands export does exactly this with Conus Albers).\n * Returning null for those left the layer in its source units, so it rendered\n * off the map with \"Invalid LngLat latitude value\" and no explanation.\n */\nfunction resolveSourceCrs(\n  db: SqlJsDatabase,\n  srsId: number | null,\n): string | null {\n  // srs_id 0 = undefined geographic, -1 = undefined cartesian (GeoPackage spec).\n  if (\n    srsId == null ||\n    srsId === 0 ||\n    srsId === -1 ||\n    WGS84_EPSG_CODES.has(srsId)\n  ) {\n    return null;\n  }\n  if (!tableExists(db, \"gpkg_spatial_ref_sys\")) return null;\n  const row = db.exec(\n    `SELECT organization, organization_coordsys_id\n     FROM gpkg_spatial_ref_sys WHERE srs_id = :id`,\n    { \":id\": srsId },\n  )[0]?.values[0];\n  if (!row) return null;\n  const organization = String(row[0] ?? \"\").toUpperCase();\n  const code = row[1] == null ? null : Number(row[1]);\n  // EPSG codes are positive integers; a malformed organization_coordsys_id\n  // (non-numeric -> NaN, or non-positive) falls through to the definition\n  // rather than tagging the layer with an invalid \"EPSG:<code>\".\n  if (\n    organization === \"EPSG\" &&\n    code != null &&\n    Number.isInteger(code) &&\n    code > 0\n  ) {\n    return WGS84_EPSG_CODES.has(code) ? null : `EPSG:${code}`;\n  }\n  return readSrsDefinition(db, srsId);\n}\n\n/**\n * Reads a spatial-reference row's WKT `definition`, or null when there is none\n * to use. Queried separately so a non-conformant file whose\n * `gpkg_spatial_ref_sys` lacks the (spec-required) `definition` column still\n * reads, instead of failing the whole layer on an unknown-column error.\n */\nfunction readSrsDefinition(db: SqlJsDatabase, srsId: number): string | null {\n  let value: unknown;\n  try {\n    value = db.exec(\n      `SELECT definition FROM gpkg_spatial_ref_sys WHERE srs_id = :id`,\n      { \":id\": srsId },\n    )[0]?.values[0]?.[0];\n  } catch {\n    return null;\n  }\n  const definition = typeof value === \"string\" ? value.trim() : \"\";\n  // The spec stores the literal \"undefined\" for the two undefined SRS rows;\n  // treat anything unusable as \"no reprojection\".\n  if (!definition || definition.toLowerCase() === \"undefined\") return null;\n  return definition;\n}\n\n/** Reads every feature of `layer` from an open database into a FeatureCollection. */\nfunction readLayerFeatures(\n  db: SqlJsDatabase,\n  layer: GeoPackageLayer,\n): FeatureCollection<Geometry | null> {\n  const result = db.exec(`SELECT * FROM ${quoteIdentifier(layer.table)}`);\n  const features: Feature<Geometry | null>[] = [];\n  if (result.length > 0) {\n    const columns = result[0].columns;\n    // Match case-insensitively: SQLite column names are case-insensitive, so the\n    // name in gpkg_geometry_columns can differ in case from SELECT *'s columns\n    // (the selectLayers join already tolerates this for table names).\n    const geometryName = layer.geometryColumn.toLowerCase();\n    const geometryIndex = columns.findIndex(\n      (column) => column.toLowerCase() === geometryName,\n    );\n    // The geometry column is declared in gpkg_geometry_columns; if SELECT * does\n    // not return it, the file is inconsistent. Fail loudly rather than emit every\n    // feature with a silent null geometry.\n    if (geometryIndex < 0) {\n      throw new Error(\n        `GeoPackage layer \"${layer.table}\" is missing its declared geometry ` +\n          `column \"${layer.geometryColumn}\".`,\n      );\n    }\n    const idIndex = layer.idColumn ? columns.indexOf(layer.idColumn) : -1;\n\n    for (const row of result[0].values) {\n      const properties: Record<string, unknown> = {};\n      for (let i = 0; i < columns.length; i += 1) {\n        if (i === geometryIndex || i === idIndex) continue;\n        const value = row[i];\n        // sql.js returns BLOB columns as Uint8Array; binary attributes are not\n        // JSON-serialisable, so drop them (matching the ST_Read path).\n        if (value instanceof Uint8Array) continue;\n        properties[columns[i]] = value;\n      }\n\n      const rawGeometry = row[geometryIndex];\n      let geometry: Geometry | null = null;\n      if (rawGeometry instanceof Uint8Array && rawGeometry.length > 0) {\n        try {\n          const wkb = stripGeoPackageHeader(rawGeometry);\n          // An empty geometry (flagged, or with no WKB body) decodes to null.\n          geometry =\n            isGeoPackageEmptyGeometry(rawGeometry) || wkb.length === 0\n              ? null\n              : decodeWkb(wkb);\n        } catch (error) {\n          // One unreadable geometry (malformed header, truncated WKB, or an\n          // unsupported curved type) must not abort the whole layer. Keep the\n          // feature with a null geometry and warn so the loss is diagnosable\n          // rather than silent.\n          console.warn(\n            `[maplibre-gl-vector] Skipped an unreadable geometry in GeoPackage layer \"${layer.table}\":`,\n            error,\n          );\n        }\n      }\n      features.push({ type: \"Feature\", geometry, properties });\n    }\n  }\n  return { type: \"FeatureCollection\", features };\n}\n\n/**\n * A SQLite/GeoPackage file begins with the \"SQLite format 3\\0\" magic.\n *\n * Only the SQLite magic is inspected, so a non-GeoPackage SQLite database with a\n * `.gpkg` name also passes; such a file then yields no feature layers in\n * {@link readGeoPackageSync} and surfaces an explicit error rather than falling\n * through to `ST_Read` (which cannot read it either).\n */\nexport function isLikelyGeoPackage(bytes: Uint8Array): boolean {\n  return looksLikeSqlite(bytes);\n}\n\n/**\n * Lists the feature-table names of a GeoPackage. Used to expand a multi-layer\n * container into one vector layer per table without touching GDAL.\n *\n * @param SQL - An initialised sql.js factory.\n * @param bytes - The GeoPackage file bytes.\n * @returns The feature-table names, in declaration order.\n */\nexport function listGeoPackageLayersSync(\n  SQL: SqlJsStatic,\n  bytes: Uint8Array,\n): string[] {\n  const db = new SQL.Database(bytes);\n  try {\n    return selectLayers(db).map((layer) => layer.table);\n  } finally {\n    db.close();\n  }\n}\n\n/**\n * Synchronous core of {@link readGeoPackage}: read every feature of the selected\n * (or first) feature layer into a GeoJSON FeatureCollection. Separated so it can\n * be unit-tested with an already-initialised sql.js factory.\n *\n * @param SQL - An initialised sql.js factory.\n * @param bytes - The GeoPackage file bytes.\n * @param sourceLayer - The feature table to read; the first layer when omitted.\n * @returns The collection plus the source EPSG code (null when already WGS84).\n */\nexport function readGeoPackageSync(\n  SQL: SqlJsStatic,\n  bytes: Uint8Array,\n  sourceLayer?: string,\n): GeoPackageReadResult {\n  const db = new SQL.Database(bytes);\n  try {\n    const layer = selectLayer(db, sourceLayer);\n    if (!layer) {\n      throw new Error(\n        sourceLayer\n          ? `GeoPackage has no feature layer named \"${sourceLayer}\".`\n          : \"No vector feature layer found in this GeoPackage.\",\n      );\n    }\n    return {\n      featureCollection: readLayerFeatures(db, layer),\n      sourceCrs: resolveSourceCrs(db, layer.srsId),\n    };\n  } finally {\n    db.close();\n  }\n}\n\n/**\n * Lists the feature-table names of a GeoPackage buffer, loading sql.js on\n * demand.\n *\n * @param bytes - The GeoPackage file bytes.\n * @param baseUrl - Optional sql.js base URL; see {@link loadSqlJs}.\n * @returns The feature-table names, in declaration order.\n */\nexport async function listGeoPackageLayers(\n  bytes: Uint8Array,\n  baseUrl?: string,\n): Promise<string[]> {\n  const SQL = await loadSqlJs(baseUrl);\n  return listGeoPackageLayersSync(SQL, bytes);\n}\n\n/**\n * Reads a GeoPackage buffer into a GeoJSON FeatureCollection via sql.js,\n * bypassing GDAL. Returns the collection plus the source EPSG code (null when\n * already WGS84) so the caller can reproject. Loads sql.js on demand.\n *\n * @param bytes - The GeoPackage file bytes.\n * @param sourceLayer - The feature table to read; the first layer when omitted.\n * @param baseUrl - Optional sql.js base URL; see {@link loadSqlJs}.\n * @returns The collection and source EPSG code.\n */\nexport async function readGeoPackage(\n  bytes: Uint8Array,\n  sourceLayer?: string,\n  baseUrl?: string,\n): Promise<GeoPackageReadResult> {\n  const SQL = await loadSqlJs(baseUrl);\n  return readGeoPackageSync(SQL, bytes, sourceLayer);\n}\n","import type { FeatureCollection, Geometry } from \"geojson\";\n\n/**\n * Serializes a FeatureCollection to UTF-8 JSON bytes without ever holding the\n * whole document as one JavaScript string.\n *\n * `JSON.stringify` throws `RangeError: Invalid string length` once the result\n * would exceed the engine's maximum string length — 536,870,888 bytes on V8 —\n * which a few hundred thousand polygon features reach easily (a statewide\n * wetlands GeoPackage does it with room to spare). Because the GeoPackage\n * reader hands DuckDB its rows as GeoJSON rather than through GDAL (see\n * `geopackage.ts`), that cap was a hard ceiling on how large a GeoPackage the\n * control could open at all.\n *\n * Serializing feature by feature keeps every intermediate string small. It also\n * lowers peak memory: the UTF-16 string and its UTF-8 copy no longer coexist\n * for the entire document, only for one feature at a time.\n *\n * @param collection - The collection to encode. Top-level members other than\n *   `features` (`type`, `bbox`, `crs`, …) are preserved.\n * @returns The encoded document as UTF-8 bytes.\n */\nexport function encodeFeatureCollection(\n  collection: FeatureCollection<Geometry | null>,\n): Uint8Array {\n  const encoder = new TextEncoder();\n  const chunks: Uint8Array[] = [];\n  let total = 0;\n  const write = (text: string): void => {\n    const bytes = encoder.encode(text);\n    chunks.push(bytes);\n    total += bytes.byteLength;\n  };\n\n  const { features, ...rest } = collection;\n  // `features` is re-added last, and JSON.stringify emits string keys in\n  // insertion order, so the head always ends with the literal `\"features\":[]}`.\n  // Dropping its final two characters leaves the array open to stream into.\n  const head = JSON.stringify({ ...rest, features: [] });\n  write(head.slice(0, -2));\n  for (let index = 0; index < features.length; index += 1) {\n    write(\n      index === 0\n        ? JSON.stringify(features[index])\n        : `,${JSON.stringify(features[index])}`,\n    );\n  }\n  write(\"]}\");\n\n  const out = new Uint8Array(total);\n  let offset = 0;\n  for (const chunk of chunks) {\n    out.set(chunk, offset);\n    offset += chunk.byteLength;\n  }\n  return out;\n}\n\n/**\n * Splits a collection into slices of at most `size` features, preserving every\n * other top-level member on each slice so each one is a valid FeatureCollection\n * in its own right.\n *\n * Used to ingest a large GeoPackage in batches: one registered file per slice\n * caps peak memory at a single batch instead of the whole layer, which is the\n * difference between opening a half-million-feature layer and exhausting the\n * tab.\n *\n * @param collection - The collection to split.\n * @param size - Maximum features per slice; must be a positive safe integer.\n * @returns One slice per batch, or a single empty slice for an empty input.\n */\nexport function sliceFeatureCollection(\n  collection: FeatureCollection<Geometry | null>,\n  size: number,\n): FeatureCollection<Geometry | null>[] {\n  // Rejected rather than coerced: NaN slips past a `<= 0` guard and yields one\n  // empty slice, silently dropping every feature, and a fractional size gives\n  // truncated `Array.prototype.slice` bounds that can repeat or omit features.\n  if (!Number.isSafeInteger(size) || size <= 0) {\n    throw new Error(\"Batch size must be a positive integer.\");\n  }\n  const { features, ...rest } = collection;\n  if (features.length === 0) return [{ ...rest, features: [] }];\n  const slices: FeatureCollection<Geometry | null>[] = [];\n  for (let start = 0; start < features.length; start += size) {\n    slices.push({ ...rest, features: features.slice(start, start + size) });\n  }\n  return slices;\n}\n","import type { Feature } from 'geojson';\nimport { importFromCdn } from '../engine/duckdbLoader';\n\n/**\n * CDN URLs for the JS tile encoder used when the loaded DuckDB build\n * lacks ST_AsMVT.\n */\nconst GEOJSON_VT_URL = 'https://cdn.jsdelivr.net/npm/geojson-vt@4.0.2/+esm';\nconst VT_PBF_URL = 'https://cdn.jsdelivr.net/npm/vt-pbf@3.1.3/+esm';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\nlet encoderPromise: Promise<{ geojsonvt: any; fromGeojsonVt: any }> | undefined;\n\nfunction loadEncoder() {\n  if (!encoderPromise) {\n    encoderPromise = Promise.all([importFromCdn(GEOJSON_VT_URL), importFromCdn(VT_PBF_URL)]).then(\n      ([gvt, vtpbf]: any[]) => ({\n        geojsonvt: gvt.default ?? gvt,\n        fromGeojsonVt: vtpbf.fromGeojsonVt ?? vtpbf.default?.fromGeojsonVt,\n      }),\n    );\n    encoderPromise.catch(() => {\n      encoderPromise = undefined;\n    });\n  }\n  return encoderPromise;\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\n/**\n * Computes the EPSG:4326 bounds of a slippy map tile.\n *\n * @param z - Tile zoom\n * @param x - Tile column\n * @param y - Tile row\n * @param buffer - Fractional tile buffer applied to all sides\n * @returns [west, south, east, north]\n */\nexport function tileBbox4326(\n  z: number,\n  x: number,\n  y: number,\n  buffer = 0,\n): [number, number, number, number] {\n  const n = 2 ** z;\n  const lonAt = (col: number) => (col / n) * 360 - 180;\n  const latAt = (row: number) => (Math.atan(Math.sinh(Math.PI * (1 - (2 * row) / n))) * 180) / Math.PI;\n  const west = lonAt(x - buffer);\n  const east = lonAt(x + 1 + buffer);\n  const north = latAt(y - buffer);\n  const south = latAt(y + 1 + buffer);\n  return [west, south, east, north];\n}\n\n/**\n * Encodes GeoJSON features into an MVT tile in JavaScript using\n * geojson-vt and vt-pbf (lazy-loaded from a CDN).\n *\n * Used as a fallback when the DuckDB spatial build has no ST_AsMVT.\n *\n * @param features - Features intersecting the tile (EPSG:4326)\n * @param layerName - MVT layer name (matches the map source-layer)\n * @param z - Tile zoom\n * @param x - Tile column\n * @param y - Tile row\n * @returns The encoded tile bytes (empty when no features)\n */\nexport async function encodeTileFromFeatures(\n  features: Feature[],\n  layerName: string,\n  z: number,\n  x: number,\n  y: number,\n): Promise<Uint8Array> {\n  if (features.length === 0) return new Uint8Array(0);\n\n  const { geojsonvt, fromGeojsonVt } = await loadEncoder();\n  const index = geojsonvt(\n    { type: 'FeatureCollection', features },\n    { maxZoom: z, indexMaxZoom: z, indexMaxPoints: 0, buffer: 64, tolerance: 3 },\n  );\n  const tile = index.getTile(z, x, y);\n  if (!tile) return new Uint8Array(0);\n\n  const encoded = fromGeojsonVt({ [layerName]: tile }, { version: 2 });\n  return new Uint8Array(encoded);\n}\n","import { unzipSync } from 'fflate';\n\n/** Strips the final extension from a zip entry path (keeps any directory). */\nfunction stripExtension(entryName: string): string {\n  return entryName.replace(/\\.[^./]+$/, '');\n}\n\n/**\n * True for the metadata entries macOS adds when it creates a zip: the\n * `__MACOSX/` resource-fork tree and the AppleDouble `._<name>` files that\n * shadow every real entry. These must be ignored, because an AppleDouble\n * `._states.shp` matches a naive `.shp` search and would otherwise be picked as\n * the shapefile (a few hundred bytes of resource-fork data GDAL rejects with\n * \"not recognized as a supported file format\") instead of the real `.shp`.\n */\nexport function isMacOsMetadataEntry(entryName: string): boolean {\n  const baseName = entryName.slice(entryName.lastIndexOf('/') + 1);\n  return entryName.startsWith('__MACOSX/') || baseName.startsWith('._');\n}\n\n/**\n * Shapefile sidecar extensions (without the dot) that ride along with a `.shp`\n * when the loose components are selected together. GDAL needs at least `.shx`\n * and `.dbf`; the projection (`.prj`), encoding (`.cpg`) and spatial-index\n * sidecars are registered too when present so they are honored and do not load\n * as their own (unreadable) layers.\n */\nexport const SHAPEFILE_SIDECAR_EXTENSIONS = new Set([\n  'shx',\n  'dbf',\n  'prj',\n  'cpg',\n  'sbn',\n  'sbx',\n  'qix',\n  'qpj',\n  'cst',\n  'aih',\n  'ain',\n  'atx',\n  'ixs',\n  'mxs',\n  'fbn',\n  'fbx',\n]);\n\n/** A `.shp` paired with the sidecar files selected alongside it. */\nexport interface ShapefileGroup<T> {\n  /** A `.shp` file, or any non-shapefile file (which has no companions). */\n  file: T;\n  /** Sidecar files sharing the `.shp`'s base name (empty for non-`.shp`). */\n  companions: T[];\n}\n\nfunction lowerExtension(name: string): string {\n  const dot = name.lastIndexOf('.');\n  return dot < 0 ? '' : name.slice(dot + 1).toLowerCase();\n}\n\nfunction lowerBaseName(name: string): string {\n  const dot = name.lastIndexOf('.');\n  return (dot < 0 ? name : name.slice(0, dot)).toLowerCase();\n}\n\n/**\n * Groups a batch of selected files so each `.shp` carries the sidecar files\n * picked alongside it (same base name, a known shapefile sidecar extension),\n * and those sidecars do not also load as their own layers.\n *\n * Files that are not part of a shapefile pass through unchanged with no\n * companions, preserving their original order. A sidecar with no matching\n * `.shp` in the batch is left as a standalone file (it is the caller's, and\n * may be a legitimate `.dbf`/`.csv`-style table).\n *\n * @param files - The selected files (anything with a `name`).\n * @returns One group per file that should load, in input order.\n */\nexport function groupShapefileComponents<T extends { name: string }>(\n  files: T[],\n): Array<ShapefileGroup<T>> {\n  const shpFiles = files.filter((f) => /\\.shp$/i.test(f.name));\n  const claimed = new Set<T>();\n  const companionsByShp = new Map<T, T[]>();\n\n  for (const shp of shpFiles) {\n    const base = lowerBaseName(shp.name);\n    const companions = files.filter(\n      (f) =>\n        f !== shp &&\n        !/\\.shp$/i.test(f.name) &&\n        lowerBaseName(f.name) === base &&\n        SHAPEFILE_SIDECAR_EXTENSIONS.has(lowerExtension(f.name)),\n    );\n    companions.forEach((c) => claimed.add(c));\n    companionsByShp.set(shp, companions);\n  }\n\n  const groups: Array<ShapefileGroup<T>> = [];\n  for (const file of files) {\n    if (claimed.has(file)) continue;\n    groups.push({ file, companions: companionsByShp.get(file) ?? [] });\n  }\n  return groups;\n}\n\n/**\n * Registers the components of a zipped shapefile individually and returns the\n * registered `.shp` path.\n *\n * GDAL's `/vsizip/` handler cannot read a DuckDB-WASM `registerFileBuffer`\n * archive: the virtual filesystem `/vsizip/` opens through is GDAL's own, not\n * DuckDB's registered-file VFS, so `ST_Read('/vsizip/<registered>.zip')` fails\n * with \"Could not open GDAL dataset\". Unzipping in the browser and registering\n * each sidecar (`.dbf`, `.shx`, `.prj`, ...) under a shared base name lets\n * GDAL's shapefile driver resolve the siblings by name when reading the `.shp`\n * directly.\n *\n * Only the first shapefile in the archive is registered; its sidecars are the\n * entries sharing its base path. A trailing directory in the zip is dropped so\n * the components register as flat siblings.\n *\n * @param zip - The raw zip archive bytes.\n * @param baseName - The registration base (the returned path is `${baseName}.shp`).\n * @param register - Registers one file buffer with the database.\n * @returns The registered `.shp` path plus the `.prj` WKT (for reprojection).\n */\nexport async function registerZippedShapefile(\n  zip: Uint8Array,\n  baseName: string,\n  register: (name: string, bytes: Uint8Array) => Promise<void> | void,\n): Promise<RegisteredShapefile> {\n  const files = unzipSync(zip);\n  const shpEntry = Object.keys(files).find(\n    (name) => /\\.shp$/i.test(name) && !isMacOsMetadataEntry(name),\n  );\n  if (!shpEntry) {\n    throw new Error('Zip archive does not contain a .shp file.');\n  }\n\n  const base = stripExtension(shpEntry);\n  let shpPath = '';\n  let prjWkt: string | null = null;\n  for (const [entry, bytes] of Object.entries(files)) {\n    // Only this shapefile's sidecars (same base path, any extension), never a\n    // macOS AppleDouble shadow of one.\n    if (isMacOsMetadataEntry(entry) || stripExtension(entry) !== base) continue;\n    const extension = entry.slice(entry.lastIndexOf('.')).toLowerCase();\n    const registeredName = `${baseName}${extension}`;\n    // Capture the `.prj` WKT before registering, since registerFileBuffer may\n    // transfer (and detach) the buffer. It is the reprojection-source fallback\n    // when ST_Read_Meta cannot report the CRS (e.g. an OSGB36 grid-shift datum).\n    if (extension === '.prj') {\n      const text = new TextDecoder().decode(bytes).trim();\n      if (text) prjWkt = text;\n    }\n    await register(registeredName, bytes);\n    if (extension === '.shp') shpPath = registeredName;\n  }\n\n  return { shpPath, prjWkt };\n}\n\n/** What {@link registerZippedShapefile} resolves to. */\nexport interface RegisteredShapefile {\n  /** The registered `.shp` path to hand to ST_Read. */\n  shpPath: string;\n  /** The `.prj` sidecar's WKT text, or null when the archive carries none. */\n  prjWkt: string | null;\n}\n\n/** One component of a loose shapefile: its lowercased extension and bytes. */\nexport interface ShapefileComponent {\n  /** Lowercased file extension including the leading dot (e.g. `.dbf`). */\n  extension: string;\n  /** The component's raw bytes. */\n  bytes: Uint8Array;\n}\n\n/**\n * Registers the components of a loose shapefile (a `.shp` and its sidecar\n * files picked together, rather than packed in a zip) under a shared base\n * name and returns the registered `.shp` path.\n *\n * A `.shp` alone is unreadable: GDAL's shapefile driver needs at least the\n * `.shx` and `.dbf` siblings, and fails with \"GDALOpen() called on x.shp\n * recursively\" when they are missing. Registering every component the caller\n * holds under one base name lets GDAL resolve the siblings by name when\n * reading the `.shp` directly, mirroring how {@link registerZippedShapefile}\n * handles a zipped shapefile.\n *\n * @param shp - The `.shp` file bytes.\n * @param components - The sidecar components (any extension other than `.shp`).\n * @param baseName - The registration base (the returned path is `${baseName}.shp`).\n * @param register - Registers one file buffer with the database.\n * @returns The registered `.shp` path to hand to ST_Read.\n */\nexport async function registerLooseShapefile(\n  shp: Uint8Array,\n  components: ShapefileComponent[],\n  baseName: string,\n  register: (name: string, bytes: Uint8Array) => Promise<void> | void,\n): Promise<string> {\n  const shpPath = `${baseName}.shp`;\n  await register(shpPath, shp);\n  for (const { extension, bytes } of components) {\n    const ext = (extension.startsWith('.') ? extension : `.${extension}`).toLowerCase();\n    if (ext === '.shp') continue;\n    await register(`${baseName}${ext}`, bytes);\n  }\n  return shpPath;\n}\n","import { unzipSync } from 'fflate';\nimport { isMacOsMetadataEntry } from './shapefile';\n\n/**\n * KMZ archive handling.\n *\n * A KMZ is a zip whose payload is one or more KML documents (plus any\n * icons, overlays and models they reference). GDAL can read the KML\n * inside one, but only through its own `/vsizip` handler, which cannot\n * open a DuckDB-WASM `registerFileBuffer` archive: `/vsizip` reads\n * through GDAL's virtual filesystem, not DuckDB's registered-file VFS.\n * The same limitation is why a zipped shapefile is unzipped and its\n * components registered individually (see `registerZippedShapefile`).\n *\n * So a KMZ is unzipped here and its KML entry is registered on its own,\n * which readers then open directly as plain KML. This makes both a local\n * `.kmz` and a remote `.kmz` URL loadable; previously a local one failed\n * with \"not recognized as a supported file format\" and a remote one with\n * an opaque `XMLHttpRequest` error naming a sibling path GDAL had probed.\n */\n\n/** The KML entry lifted out of a KMZ archive. */\nexport interface KmzKmlEntry {\n  /** The entry's path inside the archive (for display and naming). */\n  entryName: string;\n  /** The KML document's bytes. */\n  bytes: Uint8Array;\n}\n\n/**\n * Picks the KML document a KMZ archive should be read as.\n *\n * The KML spec names the main document `doc.kml`, but writers are free to\n * use anything (NASA FIRMS, for one, ships a single timestamped name), so\n * `doc.kml` is preferred when present and the first `.kml` entry is used\n * otherwise. Entries are sorted for a deterministic pick, and the macOS\n * archive metadata (`__MACOSX/`, `._` AppleDouble shadows) is skipped so a\n * resource fork is never mistaken for the document.\n *\n * @param entryNames - Every entry path in the archive\n * @returns The chosen KML entry path, or undefined when there is none\n */\nexport function pickKmlEntry(entryNames: string[]): string | undefined {\n  const kmlEntries = entryNames\n    .filter((name) => /\\.kml$/i.test(name) && !isMacOsMetadataEntry(name))\n    .sort();\n  return (\n    kmlEntries.find(\n      (name) => name.slice(name.lastIndexOf('/') + 1).toLowerCase() === 'doc.kml',\n    ) ?? kmlEntries[0]\n  );\n}\n\n/**\n * Unzips a KMZ archive and returns the KML document inside it.\n *\n * @param kmz - The KMZ archive's bytes\n * @returns The KML entry to read\n * @throws Error when the archive is unreadable or holds no KML\n */\nexport function extractKmzKml(kmz: Uint8Array): KmzKmlEntry {\n  let files: Record<string, Uint8Array>;\n  try {\n    files = unzipSync(kmz);\n  } catch {\n    // A KMZ that is not a valid zip is usually an error page or a\n    // truncated download, which the raw fflate message does not convey.\n    throw new Error('This KMZ file could not be unzipped; it may be corrupt or incomplete.');\n  }\n  const entryName = pickKmlEntry(Object.keys(files));\n  if (!entryName) {\n    throw new Error('KMZ archive does not contain a .kml file.');\n  }\n  return { entryName, bytes: files[entryName] };\n}\n","/**\n * Reading a GeoParquet file's declared CRS out of its `geo` file metadata.\n *\n * Every other format this engine ingests goes through GDAL's `ST_Read`, whose\n * `ST_Read_Meta` reports the layer CRS, so the geometry can be reprojected to\n * WGS84 on the way in. GeoParquet is read with `read_parquet` instead, and\n * DuckDB surfaces nothing about that file's CRS in the scan, so a file stored in\n * a projected CRS used to ingest as raw eastings/northings unless the caller\n * passed `sourceCrs` by hand.\n *\n * The CRS is not lost, though: the GeoParquet specification puts it in the\n * Parquet file-level key/value metadata under the key `geo`, which DuckDB does\n * expose through `parquet_kv_metadata`. This module parses that document; the\n * query that fetches it is `geoParquetCrsQuery` in `engine/sql.ts`.\n */\n\n/**\n * The CRS to reproject a GeoParquet source from, parsed from its `geo` metadata\n * document, or null when it needs no reprojection.\n *\n * Null covers every \"already in GeoJSON's coordinate convention\" case, which the\n * specification spells three ways: an absent `crs` member (GeoParquet defaults\n * to OGC:CRS84), an explicit WGS84/CRS84 identifier, and `\"crs\": null`, which\n * declares that the coordinates are in no known CRS at all -- reprojecting those\n * would invent an answer, so they pass through untouched.\n *\n * A CRS that is present and not WGS84 is returned in the most specific form the\n * document supports, in this order:\n *\n * 1. `AUTHORITY:CODE` from the PROJJSON `id` member (`EPSG:2100`), which every\n *    writer that round-trips an EPSG code emits and which `ST_Transform`\n *    resolves most reliably.\n * 2. The PROJJSON document itself, for a CRS carrying no authority code (a\n *    custom projection); PROJ parses PROJJSON wherever it parses WKT.\n * 3. The raw string, for the pre-1.0 GeoParquet drafts that wrote the CRS as a\n *    WKT2 string rather than as PROJJSON.\n *\n * @param metadataJson - The `geo` metadata document text, or null when absent\n * @param isWgs84 - Predicate telling whether an `AUTHORITY:CODE` is WGS84 lon/lat\n * @param geometryColumn - The column actually being ingested, when known. A\n *   GeoParquet may carry several geometry columns in different CRSs, and the\n *   ingest reads whichever one it detected rather than necessarily the primary\n *   one, so its CRS is the one to transform from.\n * @returns A CRS string `ST_Transform` accepts, or null to skip reprojection\n */\nexport function geoParquetSourceCrs(\n  metadataJson: string | null | undefined,\n  isWgs84: (crs: string) => boolean,\n  geometryColumn?: string,\n): string | null {\n  if (!metadataJson) return null;\n\n  let metadata: unknown;\n  try {\n    metadata = JSON.parse(metadataJson);\n  } catch {\n    // A `geo` key that is not JSON is not a GeoParquet document; treat the file\n    // as carrying no CRS rather than failing the ingest.\n    return null;\n  }\n\n  const column = geometryColumnMetadata(metadata, geometryColumn);\n  if (!column || !(\"crs\" in column)) return null;\n\n  const crs = (column as { crs?: unknown }).crs;\n  // An explicit null declares \"no CRS\", distinct from an absent member (CRS84).\n  if (crs === null || crs === undefined) return null;\n\n  const resolved = crsString(crs);\n  if (!resolved || isWgs84(resolved)) return null;\n  return resolved;\n}\n\n/**\n * The metadata entry for the geometry column being ingested: the named column\n * when the document describes it, else the one `primary_column` names, else the\n * first column listed (so a hand-written document with a single geometry column\n * still resolves).\n *\n * The named column comes first because a GeoParquet may hold several geometry\n * columns in different CRSs; transforming the ingested column with the primary\n * column's CRS would place the layer somewhere else entirely.\n *\n * @param metadata - The parsed `geo` document\n * @param geometryColumn - The column being ingested, when known\n * @returns The column's metadata object, or null when there is none\n */\nfunction geometryColumnMetadata(\n  metadata: unknown,\n  geometryColumn?: string,\n): object | null {\n  const columns = (metadata as { columns?: unknown })?.columns;\n  if (!columns || typeof columns !== \"object\") return null;\n  const entries = Object.entries(columns as Record<string, unknown>).filter(\n    (entry): entry is [string, object] =>\n      typeof entry[1] === \"object\" && entry[1] !== null,\n  );\n  if (entries.length === 0) return null;\n\n  const primary = (metadata as { primary_column?: unknown }).primary_column;\n  for (const wanted of [geometryColumn, primary]) {\n    if (typeof wanted !== \"string\") continue;\n    const named = entries.find(([name]) => name === wanted);\n    if (named) return named[1];\n  }\n  return entries[0][1];\n}\n\n/**\n * One column's `crs` value rendered as a string `ST_Transform` accepts.\n *\n * @param crs - The `crs` member: PROJJSON, a WKT string, or something else\n * @returns The CRS as a string, or null when the value carries none\n */\nfunction crsString(crs: unknown): string | null {\n  if (typeof crs === \"string\") return crs.trim() || null;\n  if (typeof crs !== \"object\") return null;\n\n  const id = (crs as { id?: unknown }).id;\n  const authority = (id as { authority?: unknown })?.authority;\n  const code = (id as { code?: unknown })?.code;\n  if (\n    typeof authority === \"string\" &&\n    (typeof code === \"string\" || typeof code === \"number\")\n  ) {\n    return `${authority.trim().toUpperCase()}:${String(code).trim()}`;\n  }\n\n  // No authority code: hand PROJ the whole PROJJSON definition instead, so a\n  // custom projection still reprojects rather than ingesting as raw coordinates.\n  return JSON.stringify(crs);\n}\n","import type { Feature, FeatureCollection, Geometry } from 'geojson';\nimport { decodeWkb } from './geopackage';\n\n/**\n * ISO WKB base type codes of the surface geometries {@link decodeWkb} turns into\n * a MultiPolygon/Polygon: PolyhedralSurface (15), TIN (16), Triangle (17). The\n * Z/M variants (1015-1017, 2015-2017, 3015-3017) share these `code % 1000`.\n */\nconst SURFACE_WKB_TYPE_CODES = new Set([15, 16, 17]);\n\n/**\n * True when a DuckDB query failed specifically because its Spatial WKB reader\n * cannot represent a **surface** geometry (TIN / PolyhedralSurface / Triangle) —\n * the encoding GDAL emits for ESRI MultiPatch shapefiles (3D buildings), e.g.\n * `Could not parse WKB input: WKB type 'TIN Z' is not supported! (type id: 1016,\n * SRID: 0)`. Only these surfaces trigger the raw-WKB fallback, which\n * {@link decodeWkb} can decode.\n *\n * Curved geometries (CircularString, CompoundCurve, CurvePolygon, MultiCurve,\n * MultiSurface — codes 8-12) raise the same \"WKB type ... is not supported\"\n * template but stay undecodable, so they are deliberately excluded: routing them\n * into the fallback would silently produce an empty (all-null-geometry) layer\n * instead of failing loudly. The match therefore requires a surface type name or\n * a surface type id (15/16/17) in the message, not just the generic error shape.\n */\nexport function isUnsupportedSurfaceWkbError(error: unknown): boolean {\n  const message = error instanceof Error ? error.message : String(error);\n  const lower = message.toLowerCase();\n  const isUnsupportedWkb =\n    lower.includes('could not parse wkb') ||\n    (lower.includes('wkb type') && lower.includes('not supported'));\n  if (!isUnsupportedWkb) return false;\n  // Prefer the numeric type id when present (unambiguous); otherwise fall back to\n  // the type name DuckDB quotes ('TIN Z', 'PolyhedralSurface Z', 'Triangle').\n  const idMatch = message.match(/type id:\\s*(\\d+)/i);\n  if (idMatch) {\n    return SURFACE_WKB_TYPE_CODES.has(Number(idMatch[1]) % 1000);\n  }\n  // `tin` needs word boundaries so it does not match substrings like \"casting\";\n  // `polyhedral`/`triangle` are distinctive as-is (\"PolyhedralSurface\" has no\n  // boundary before \"Surface\").\n  return /\\btin\\b|polyhedral|triangle/i.test(message);\n}\n\n/**\n * Coerce a DuckDB geometry cell to WKB bytes: a BLOB arrives as a `Uint8Array`,\n * a base64-encoded WKB string as a `string`. Returns null for an empty/absent\n * value or an undecodable base64 string.\n */\nfunction wkbCellToBytes(value: unknown): Uint8Array | null {\n  if (value instanceof Uint8Array) return value.length > 0 ? value : null;\n  if (typeof value === 'string' && value.length > 0) {\n    try {\n      return Uint8Array.from(atob(value), (char) => char.charCodeAt(0));\n    } catch {\n      return null;\n    }\n  }\n  return null;\n}\n\n/** Normalize a DuckDB cell into a JSON-serializable GeoJSON property value. */\nfunction sanitizeProperty(value: unknown): unknown {\n  if (value === null || value === undefined) return null;\n  if (typeof value === 'bigint') {\n    return Number.isSafeInteger(Number(value)) ? Number(value) : value.toString();\n  }\n  if (value instanceof Date) return value.toISOString();\n  if (value instanceof Uint8Array) return null;\n  if (typeof value === 'object') {\n    try {\n      return JSON.parse(\n        JSON.stringify(value, (_key, v) =>\n          typeof v === 'bigint'\n            ? Number.isSafeInteger(Number(v))\n              ? Number(v)\n              : v.toString()\n            : v,\n        ),\n      );\n    } catch {\n      return String(value);\n    }\n  }\n  return value;\n}\n\n/**\n * Build a FeatureCollection from `keep_wkb := true` rows, decoding each row's raw\n * WKB with {@link decodeWkb} (which maps TIN / PolyhedralSurface surfaces to a\n * MultiPolygon). The geometry cell is accepted as either a BLOB (`Uint8Array`)\n * or a base64 WKB string. A value that cannot be decoded yields a null geometry\n * rather than aborting the whole file, and the WKB column is dropped from the\n * feature's properties.\n *\n * @param rows - Rows from a `SELECT * FROM ST_Read(..., keep_wkb := true)` query.\n * @param wkbColumn - The name of the WKB geometry column.\n */\nexport function wkbRowsToFeatureCollection(\n  rows: Array<Record<string, unknown>>,\n  wkbColumn: string,\n): FeatureCollection<Geometry | null> {\n  const features = rows.map((row) => {\n    const bytes = wkbCellToBytes(row[wkbColumn]);\n    let geometry: Geometry | null = null;\n    if (bytes) {\n      try {\n        geometry = decodeWkb(bytes);\n      } catch {\n        // One malformed/unrepresentable geometry must not fail the whole layer.\n        geometry = null;\n      }\n    }\n    const properties: Record<string, unknown> = {};\n    for (const [key, value] of Object.entries(row)) {\n      if (key === wkbColumn || value instanceof Uint8Array) continue;\n      properties[key] = sanitizeProperty(value);\n    }\n    return {\n      type: 'Feature',\n      geometry,\n      properties,\n    } satisfies Feature<Geometry | null>;\n  });\n  return { type: 'FeatureCollection', features };\n}\n","import type { Feature, FeatureCollection, Geometry } from \"geojson\";\nimport type { GeometryCategory } from \"../core/types\";\nimport type { IEngine, IngestOptions, IngestSummary } from \"./types\";\nimport type { Bbox } from \"../utils/geometry\";\nimport { mergeGeometryCategory } from \"../utils/geometry\";\nimport { loadDuckDB, type LoadedDuckDB } from \"./duckdbLoader\";\nimport { ensureGpkgFeatureCount } from \"./gpkgOgrContents\";\nimport { listGeoPackageLayers, readGeoPackage } from \"./geopackage\";\nimport {\n  encodeFeatureCollection,\n  sliceFeatureCollection,\n} from \"./geojsonBytes\";\nimport { encodeTileFromFeatures, tileBbox4326 } from \"../tiles/mvtFallback\";\nimport { assertRemoteFileSupported, probeRemoteSize } from \"../utils/remote\";\nimport {\n  LON_LAT_COLUMN_PAIRS,\n  WKT_COLUMN_NAMES,\n  bboxSummaryQuery,\n  columnsQueryFromDescribe,\n  createTableFromLonLatSql,\n  createTableFromWktSql,\n  createTableFromGeometrySql,\n  createViewFromGeometrySql,\n  detectGeometryColumn,\n  exportGeoJSONQuery,\n  gdalPath,\n  GEOPARQUET_METADATA_COLUMN,\n  geoParquetCrsQuery,\n  geometryTypesQuery,\n  isBboxCoveringColumn,\n  keepWkbReaderFor,\n  layersMetaQuery,\n  mvtTileQuery,\n  mvtTileStreamQuery,\n  prepareTilesSql,\n  propertyValuesQuery,\n  quoteIdent,\n  quoteLiteral,\n  readerFor,\n  sampledGeometryTypesQuery,\n  sourceCrsMetaQuery,\n  summaryQuery,\n  tileFeaturesQuery,\n  type DetectedGeometryColumn,\n} from \"./sql\";\nimport {\n  registerLooseShapefile,\n  registerZippedShapefile,\n} from \"../formats/shapefile\";\nimport { extractKmzKml } from \"../formats/kmz\";\nimport { geoParquetSourceCrs } from \"../formats/geoparquetCrs\";\nimport {\n  isUnsupportedSurfaceWkbError,\n  wkbRowsToFeatureCollection,\n} from \"./surfaceWkb\";\n\n/**\n * Whether an `AUTHORITY:CODE` CRS string names WGS84 lon/lat, for which\n * reprojection to EPSG:4326 is a no-op: EPSG:4326 (2D), EPSG:4979 (3D geographic,\n * same lat/lon), and OGC:CRS84 (lon/lat order). Skipping the transform for these\n * keeps the common already-WGS84 case cheap.\n *\n * @param crs - An `AUTHORITY:CODE` CRS string\n * @returns True when the CRS is WGS84 lon/lat\n */\n/**\n * Property name that carries a feature's source index through the reproject\n * round-trip in {@link DuckDBEngine.reprojectGeoJSON}, so each reprojected\n * geometry can be matched back to its original feature. Prefixed to avoid\n * colliding with a real attribute in the input.\n */\nconst FID_COLUMN = \"__mgv_reproject_fid\";\n\n/**\n * Features per registered file when ingesting a GeoPackage.\n *\n * Bounds peak memory to one batch rather than the whole layer. Large enough\n * that a typical layer is still a single round trip, small enough that a\n * half-million-feature layer never materializes a document near the maximum\n * JavaScript string length.\n */\nconst GEOPACKAGE_INGEST_BATCH = 50_000;\n\nfunction isWgs84AuthCrs(crs: string): boolean {\n  switch (crs.toUpperCase()) {\n    case \"EPSG:4326\":\n    case \"EPSG:4979\":\n    case \"OGC:CRS84\":\n      return true;\n    default:\n      return false;\n  }\n}\n\n/**\n * Options for creating the DuckDB engine.\n */\nexport interface CreateEngineOptions {\n  /** Progress message callback (e.g. for the panel status line) */\n  onProgress?: (message: string) => void;\n  /**\n   * Base URL to load duckdb-wasm from instead of jsDelivr. See\n   * {@link loadDuckDB}.\n   */\n  baseUrl?: string;\n  /**\n   * Base URL to load sql.js from instead of jsDelivr. sql.js is used to repair\n   * GeoPackages missing `gpkg_ogr_contents` before reading. See\n   * {@link ensureGpkgFeatureCount}.\n   */\n  sqlJsBaseUrl?: string;\n  /**\n   * Path/URL to a prebuilt spatial extension. When set, the remote\n   * `INSTALL spatial` is skipped in favour of `LOAD '<path>'`. See\n   * {@link loadDuckDB}.\n   */\n  spatialExtensionPath?: string;\n}\n\n/**\n * Serializes async work onto a single promise chain. DuckDB-WASM runs\n * queries on one connection, so all engine work (ingest, exports, and\n * every tile) is queued to avoid interleaving.\n */\nclass QueryQueue {\n  private _tail: Promise<unknown> = Promise.resolve();\n\n  /**\n   * Appends a task to the queue.\n   *\n   * @param task - The async task to run\n   * @param signal - Optional abort signal checked when the task is\n   *   dequeued, so stale tile requests are skipped cheaply\n   * @returns The task result\n   */\n  enqueue<T>(task: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n    const run = this._tail.then(() => {\n      if (signal?.aborted) {\n        throw new DOMException(\"The operation was aborted.\", \"AbortError\");\n      }\n      return task();\n    });\n    this._tail = run.catch(() => undefined);\n    return run;\n  }\n}\n\ninterface TableMeta {\n  /** Non-geometry columns exported as feature properties */\n  propertyColumns: string[];\n  /** Whether geom_3857 and the spatial index exist */\n  prepared: boolean;\n  /** Whether this is a streaming view rather than a table */\n  streamed: boolean;\n  /** GeoParquet bbox covering column, when present */\n  bboxColumn?: string;\n  /** Object URL to revoke with the table */\n  objectUrl?: string;\n}\n\ninterface ColumnInfo {\n  name: string;\n  type: string;\n}\n\n/**\n * Converts an arrow cell value to a JSON-safe property value.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction sanitizeValue(value: any): unknown {\n  if (value === null || value === undefined) return null;\n  switch (typeof value) {\n    case \"bigint\":\n      return Number.isSafeInteger(Number(value))\n        ? Number(value)\n        : value.toString();\n    case \"number\":\n    case \"string\":\n    case \"boolean\":\n      return value;\n    case \"object\":\n      if (value instanceof Date) return value.toISOString();\n      if (value instanceof Uint8Array) return null;\n      try {\n        return JSON.parse(\n          JSON.stringify(value, (_key, v) =>\n            typeof v === \"bigint\"\n              ? Number.isSafeInteger(Number(v))\n                ? Number(v)\n                : v.toString()\n              : v,\n          ),\n        );\n      } catch {\n        return String(value);\n      }\n    default:\n      return String(value);\n  }\n}\n\nfunction numberFromCount(value: unknown): number {\n  if (typeof value === \"number\") return value;\n  if (typeof value === \"bigint\") return Number(value);\n  if (typeof value === \"string\") return Number(value);\n  return 0;\n}\n\n/**\n * Maps a DuckDB ST_GeometryType value to a broad category.\n */\nfunction categoryFromTypeName(name: string): GeometryCategory {\n  const upper = name.toUpperCase();\n  if (upper.includes(\"POINT\")) return \"point\";\n  if (upper.includes(\"LINESTRING\")) return \"line\";\n  if (upper.includes(\"POLYGON\")) return \"polygon\";\n  return upper.includes(\"GEOMETRYCOLLECTION\") ? \"mixed\" : \"unknown\";\n}\n\n/**\n * IEngine implementation backed by DuckDB-WASM with the spatial\n * extension, lazy-loaded from jsDelivr.\n */\nexport class DuckDBEngine implements IEngine {\n  private _loaded: LoadedDuckDB;\n  private _queue = new QueryQueue();\n  private _tables = new Map<string, TableMeta>();\n  /**\n   * Registered virtual file per Blob, so a multi-layer file ingested\n   * several times (once per layer) is uploaded into the WASM FS once.\n   * Shared files live until dispose; only per-table object URLs are\n   * released with their table.\n   */\n  private _sharedFiles = new Map<Blob, string>();\n  /**\n   * GeoPackage bytes per source, so the listLayers probe and the per-layer\n   * ingest(s) of a multi-layer file each read the buffer (a local\n   * `arrayBuffer()` or a remote fetch) only once.\n   */\n  private _geoPackageBytes = new Map<string | Blob, Promise<Uint8Array>>();\n  /**\n   * The registered `.kml` extracted from a KMZ, keyed by source, so the\n   * listLayers probe and each per-layer ingest of a multi-layer KMZ share one\n   * unzip (and, for a URL, one fetch) instead of repeating it per layer.\n   */\n  private _kmzKmlPaths = new Map<string | Blob, Promise<string>>();\n  /**\n   * The `.prj` WKT of a registered zipped shapefile, keyed by its registered\n   * `.shp` path. A zip carries no `companionFiles`, so this preserves its\n   * projection for the reprojection fallback in {@link _createTable}.\n   */\n  private _prjWktByPath = new Map<string, string>();\n  private _sqlJsBaseUrl?: string;\n  /** Monotonic suffix so concurrent reprojections register distinct files. */\n  private _reprojectSeq = 0;\n\n  /**\n   * Creates an engine wrapper over a loaded DuckDB instance.\n   *\n   * @param loaded - The loaded database and connection\n   * @param sqlJsBaseUrl - Optional sql.js base URL for the GeoPackage repair\n   */\n  constructor(loaded: LoadedDuckDB, sqlJsBaseUrl?: string) {\n    this._loaded = loaded;\n    this._sqlJsBaseUrl = sqlJsBaseUrl;\n  }\n\n  /** Whether the loaded build supports native ST_AsMVT tiles. */\n  get supportsMVT(): boolean {\n    return this._loaded.supportsMVT;\n  }\n\n  /** DuckDB core version string. */\n  get version(): string {\n    return this._loaded.version;\n  }\n\n  /** @inheritdoc */\n  ingest(\n    source: string | File | Blob,\n    tableName: string,\n    options: IngestOptions,\n  ): Promise<IngestSummary> {\n    return this._queue.enqueue(async () => {\n      const streamed =\n        options.mode === \"stream\" && options.format === \"geoparquet\";\n      const meta: TableMeta = {\n        propertyColumns: [],\n        prepared: false,\n        streamed,\n      };\n\n      let byteSize: number | undefined;\n      // The CRS a streaming view reprojects from, resolved inside\n      // `_createStreamView`; null when it reprojects nothing.\n      let streamCrs: string | null = null;\n      // GeoPackages are read with sql.js and reprojected through DuckDB, never\n      // through GDAL's ST_Read, which hangs/crashes on the single-threaded WASM\n      // build (see geopackage.ts).\n      if (options.format === \"geopackage\" && !streamed) {\n        const bytes = await this._geoPackageBytesFor(source);\n        byteSize = bytes.byteLength;\n        await this._createTableFromGeoPackage(tableName, bytes, options);\n      } else {\n        const path = await this._registerSource(source, tableName, options);\n        byteSize =\n          typeof Blob !== \"undefined\" && source instanceof Blob\n            ? source.size\n            : await probeRemoteSize(source as string);\n        if (streamed) {\n          streamCrs = await this._createStreamView(tableName, path, options);\n        } else {\n          try {\n            await this._createTable(tableName, path, options);\n          } catch (err) {\n            // ST_Read on registered buffers fails on some builds; retry local\n            // files through an object URL the worker can fetch.\n            const retried = await this._retryWithObjectUrl(\n              err,\n              source,\n              tableName,\n              options,\n              meta,\n            );\n            if (!retried) throw err;\n          }\n        }\n      }\n\n      const columns = await this._describeTable(tableName);\n      // A GeoParquet covering bbox is expressed in the file's source CRS.\n      // Once `geom` has been reprojected to WGS84 — by an override or by the\n      // CRS the file's own `geo` metadata declares — that raw bbox can no\n      // longer be compared with WGS84 tile bounds. Fall back to geometry\n      // filtering in this uncommon streaming case rather than pruning away\n      // valid rows with mismatched coordinate systems.\n      meta.bboxColumn =\n        streamed && streamCrs\n          ? undefined\n          : columns.find((c) => isBboxCoveringColumn(c.name, c.type))?.name;\n      meta.propertyColumns = columns\n        .filter(\n          (c) =>\n            c.type !== \"GEOMETRY\" &&\n            c.name !== \"geom_3857\" &&\n            c.name !== meta.bboxColumn,\n        )\n        .map((c) => c.name);\n      this._tables.set(tableName, meta);\n\n      const summary = await this._summarize(tableName, meta);\n      return {\n        ...summary,\n        tableName,\n        fields: [...meta.propertyColumns],\n        byteSize,\n        streamed,\n      };\n    });\n  }\n\n  /** @inheritdoc */\n  exportGeoJSON(tableName: string): Promise<FeatureCollection> {\n    return this._queue.enqueue(async () => {\n      const meta = this._requireTable(tableName);\n      const result = await this._loaded.conn.query(\n        exportGeoJSONQuery(tableName, meta.propertyColumns),\n      );\n      const features: Feature[] = result.toArray().map((row) => {\n        const geometry = JSON.parse(String(row.__geojson)) as Geometry;\n        const properties: Record<string, unknown> = {};\n        for (const column of meta.propertyColumns) {\n          properties[column] = sanitizeValue(row[column]);\n        }\n        return { type: \"Feature\", geometry, properties };\n      });\n      return { type: \"FeatureCollection\", features };\n    });\n  }\n\n  /** @inheritdoc */\n  getPropertyValues(tableName: string, property: string): Promise<unknown[]> {\n    return this._queue.enqueue(async () => {\n      const meta = this._requireTable(tableName);\n      if (!meta.propertyColumns.includes(property)) return [];\n      const result = await this._loaded.conn.query(\n        propertyValuesQuery(tableName, property),\n      );\n      return result.toArray().map((row) => sanitizeValue(row.__value));\n    });\n  }\n\n  /** @inheritdoc */\n  reprojectGeoJSON(\n    collection: FeatureCollection,\n    sourceCrs: string,\n  ): Promise<FeatureCollection> {\n    return this._queue.enqueue(async () => {\n      const features = collection.features;\n      // Feed DuckDB only the geometries, each tagged with its feature index, so\n      // the reprojected geometry can be zipped back to the original feature's\n      // properties without round-tripping arbitrary (possibly nested) property\n      // values through GDAL's GeoJSON reader.\n      const geomsOnly: FeatureCollection = {\n        type: \"FeatureCollection\",\n        features: features.map((feature, index) => ({\n          type: \"Feature\",\n          properties: { [FID_COLUMN]: index },\n          geometry: feature.geometry,\n        })),\n      };\n      const geojsonName = `reproject_${this._reprojectSeq++}.geojson`;\n      await this._loaded.db.registerFileBuffer(\n        geojsonName,\n        encodeFeatureCollection(geomsOnly),\n      );\n      try {\n        const result = await this._loaded.conn.query(\n          `SELECT ${quoteIdent(FID_COLUMN)} AS fid, ` +\n            `ST_AsGeoJSON(ST_Transform(geom, ${quoteLiteral(sourceCrs)}, 'EPSG:4326', always_xy := true)) AS __geojson ` +\n            `FROM ST_Read(${quoteLiteral(geojsonName)}) WHERE geom IS NOT NULL`,\n        );\n        // Map each reprojected geometry back onto its source feature by index, so\n        // the result is robust to DuckDB returning rows out of source order.\n        const reprojected = new Map<number, Geometry>();\n        for (const row of result.toArray()) {\n          reprojected.set(\n            Number(row.fid),\n            JSON.parse(String(row.__geojson)) as Geometry,\n          );\n        }\n        return {\n          type: \"FeatureCollection\",\n          features: features.map((feature, index) => ({\n            ...feature,\n            geometry: reprojected.get(index) ?? feature.geometry,\n          })),\n        };\n      } finally {\n        await this._loaded.db.dropFile(geojsonName).catch(() => undefined);\n      }\n    });\n  }\n\n  /** @inheritdoc */\n  prepareTiles(tableName: string): Promise<void> {\n    return this._queue.enqueue(async () => {\n      const meta = this._requireTable(tableName);\n      if (meta.prepared) return;\n\n      // Streamed sources are queried in place per tile; there is no\n      // table to transform or index.\n      if (meta.streamed) {\n        meta.prepared = true;\n        return;\n      }\n\n      const statements = prepareTilesSql(tableName);\n      for (const statement of statements.transform) {\n        await this._loaded.conn.query(statement);\n      }\n      try {\n        await this._loaded.conn.query(statements.index);\n      } catch {\n        // R-Tree support varies across builds; tiles still work via scans.\n      }\n      meta.prepared = true;\n    });\n  }\n\n  /** @inheritdoc */\n  getTile(\n    tableName: string,\n    layerName: string,\n    z: number,\n    x: number,\n    y: number,\n    signal?: AbortSignal,\n  ): Promise<Uint8Array> {\n    return this._queue.enqueue(async () => {\n      const meta = this._requireTable(tableName);\n\n      if (this._loaded.supportsMVT) {\n        const query = meta.streamed\n          ? mvtTileStreamQuery(\n              tableName,\n              layerName,\n              z,\n              x,\n              y,\n              tileBbox4326(z, x, y, 64 / 4096),\n              meta.propertyColumns,\n              meta.bboxColumn,\n            )\n          : mvtTileQuery(tableName, layerName, z, x, y, meta.propertyColumns);\n        const result = await this._loaded.conn.query(query);\n        const value = result.toArray()[0]?.tile as\n          | Uint8Array\n          | null\n          | undefined;\n        // Copy out of WASM-backed memory before handing to MapLibre.\n        return value ? new Uint8Array(value) : new Uint8Array(0);\n      }\n\n      // Fallback: query intersecting features and encode the tile in JS.\n      const bbox = tileBbox4326(z, x, y, 64 / 4096);\n      const result = await this._loaded.conn.query(\n        tileFeaturesQuery(tableName, bbox, meta.propertyColumns),\n      );\n      const features: Feature[] = result.toArray().map((row) => {\n        const geometry = JSON.parse(String(row.__geojson)) as Geometry;\n        const properties: Record<string, unknown> = {};\n        for (const column of meta.propertyColumns) {\n          properties[column] = sanitizeValue(row[column]);\n        }\n        return { type: \"Feature\", geometry, properties };\n      });\n      return encodeTileFromFeatures(features, layerName, z, x, y);\n    }, signal);\n  }\n\n  /** @inheritdoc */\n  dropTable(tableName: string): Promise<void> {\n    return this._queue.enqueue(async () => {\n      const meta = this._tables.get(tableName);\n      const kind = meta?.streamed ? \"VIEW\" : \"TABLE\";\n      await this._loaded.conn.query(\n        `DROP ${kind} IF EXISTS ${quoteIdent(tableName)}`,\n      );\n      // Shared registered files are NOT dropped here: another table\n      // ingested from the same Blob may still read them. They are\n      // released when the engine is disposed.\n      if (meta?.objectUrl) {\n        URL.revokeObjectURL(meta.objectUrl);\n      }\n      this._tables.delete(tableName);\n    });\n  }\n\n  /** @inheritdoc */\n  async dispose(): Promise<void> {\n    for (const meta of this._tables.values()) {\n      if (meta.objectUrl) URL.revokeObjectURL(meta.objectUrl);\n    }\n    this._tables.clear();\n    for (const name of this._sharedFiles.values()) {\n      await this._loaded.db.dropFile(name).catch(() => undefined);\n    }\n    this._sharedFiles.clear();\n    for (const path of this._kmzKmlPaths.values()) {\n      // A rejected entry registered nothing, so there is nothing to drop.\n      const name = await path.catch(() => undefined);\n      if (name) await this._loaded.db.dropFile(name).catch(() => undefined);\n    }\n    this._kmzKmlPaths.clear();\n    this._geoPackageBytes.clear();\n    this._prjWktByPath.clear();\n    await this._loaded.conn.close().catch(() => undefined);\n    await this._loaded.db.terminate().catch(() => undefined);\n  }\n\n  /**\n   * Registers a source with the database and returns the path readers\n   * should use. URLs pass through untouched.\n   */\n  private async _registerSource(\n    source: string | File | Blob,\n    registrationName: string,\n    options: IngestOptions,\n  ): Promise<string> {\n    // A KMZ is a zip GDAL can only open through /vsizip, which cannot reach a\n    // registered buffer or a URL here; unzip it and register the KML instead.\n    if (options.format === \"kmz\") {\n      return this._kmzKmlPathFor(source, registrationName);\n    }\n\n    if (typeof source === \"string\") {\n      // Defense in depth: the layer manager checks before loading the\n      // engine; the shared cache makes this probe free.\n      await assertRemoteFileSupported(source);\n      return source;\n    }\n\n    const shared = this._sharedFiles.get(source);\n    if (shared) return shared;\n\n    const extension = options.fileName?.match(/\\.([a-z0-9]+)$/i)?.[1] ?? \"bin\";\n    const name = `${registrationName}.${extension.toLowerCase()}`;\n    let buffer: Uint8Array = new Uint8Array(await source.arrayBuffer());\n\n    // GeoPackages without gpkg_ogr_contents crash ST_Read on single-threaded\n    // DuckDB-WASM; repair the buffer before registering it. See\n    // gpkgOgrContents.ts.\n    if (options.format === \"geopackage\") {\n      buffer = await ensureGpkgFeatureCount(buffer, this._sqlJsBaseUrl);\n    }\n\n    // GDAL's /vsizip handler cannot read a DuckDB-WASM registerFileBuffer\n    // archive (the virtual filesystem it opens through is GDAL's own, not\n    // DuckDB's registered-file VFS), so a zipped shapefile is unzipped and its\n    // components are registered individually; readers then open the .shp\n    // directly rather than via /vsizip.\n    if (options.format === \"shapefile\" && /\\.zip$/i.test(name)) {\n      const { shpPath, prjWkt } = await registerZippedShapefile(\n        buffer,\n        registrationName,\n        (componentName, bytes) =>\n          this._loaded.db.registerFileBuffer(componentName, bytes),\n      );\n      // A zip carries no `companionFiles`, so remember its `.prj` WKT keyed by\n      // the registered path for the reprojection fallback in `_createTable`.\n      if (prjWkt) this._prjWktByPath.set(shpPath, prjWkt);\n      this._sharedFiles.set(source, shpPath);\n      return shpPath;\n    }\n\n    // A loose `.shp` picked together with its sidecars (`.shx`, `.dbf`, ...):\n    // register every component under one base name so GDAL resolves the\n    // siblings when reading the `.shp` directly. Without this a lone `.shp`\n    // fails with \"GDALOpen() called on x.shp recursively\".\n    if (options.format === \"shapefile\" && options.companionFiles?.length) {\n      const components = await Promise.all(\n        options.companionFiles.map(async (file) => ({\n          extension: file.name.slice(file.name.lastIndexOf(\".\")),\n          bytes: new Uint8Array(await file.arrayBuffer()),\n        })),\n      );\n      const shpPath = await registerLooseShapefile(\n        buffer,\n        components,\n        registrationName,\n        (componentName, bytes) =>\n          this._loaded.db.registerFileBuffer(componentName, bytes),\n      );\n      this._sharedFiles.set(source, shpPath);\n      return shpPath;\n    }\n\n    await this._loaded.db.registerFileBuffer(name, buffer);\n    this._sharedFiles.set(source, name);\n    return name;\n  }\n\n  /**\n   * Unzips a KMZ source once and registers the KML inside it, returning the\n   * registered path readers should open. Cached per source so a multi-layer\n   * KMZ unzips (and, for a URL, downloads) once rather than per layer.\n   */\n  private _kmzKmlPathFor(\n    source: string | File | Blob,\n    registrationName: string,\n  ): Promise<string> {\n    const cached = this._kmzKmlPaths.get(source);\n    if (cached) return cached;\n    const path = (async () => {\n      let bytes: Uint8Array;\n      if (typeof source === \"string\") {\n        await assertRemoteFileSupported(source);\n        const response = await fetch(source);\n        if (!response.ok) {\n          throw new Error(\n            `Failed to fetch KMZ (${response.status} ${response.statusText}).`,\n          );\n        }\n        bytes = new Uint8Array(await response.arrayBuffer());\n      } else {\n        bytes = new Uint8Array(await source.arrayBuffer());\n      }\n      const { bytes: kml } = extractKmzKml(bytes);\n      // A `.kml` name so GDAL picks its KML driver from the extension.\n      const name = `${registrationName}.kml`;\n      await this._loaded.db.registerFileBuffer(name, kml);\n      return name;\n    })();\n    // Drop a failed read from the cache so a later attempt can retry.\n    path.catch(() => this._kmzKmlPaths.delete(source));\n    this._kmzKmlPaths.set(source, path);\n    return path;\n  }\n\n  /**\n   * Reads a GeoPackage source's bytes once and caches them, so the listLayers\n   * probe and each per-layer ingest of a multi-layer file share a single\n   * `arrayBuffer()` (local) or fetch (remote).\n   */\n  private _geoPackageBytesFor(\n    source: string | File | Blob,\n  ): Promise<Uint8Array> {\n    const cached = this._geoPackageBytes.get(source);\n    if (cached) return cached;\n    const bytes = (async () => {\n      if (typeof source === \"string\") {\n        await assertRemoteFileSupported(source);\n        const response = await fetch(source);\n        if (!response.ok) {\n          throw new Error(\n            `Failed to fetch GeoPackage (${response.status} ${response.statusText}).`,\n          );\n        }\n        return new Uint8Array(await response.arrayBuffer());\n      }\n      return new Uint8Array(await source.arrayBuffer());\n    })();\n    // Drop a failed read from the cache so a later attempt can retry.\n    bytes.catch(() => this._geoPackageBytes.delete(source));\n    this._geoPackageBytes.set(source, bytes);\n    return bytes;\n  }\n\n  /**\n   * Creates the ingest table from a GeoPackage by reading it with sql.js into\n   * GeoJSON, loading that through DuckDB's (unaffected) GeoJSON reader, and\n   * reprojecting to EPSG:4326 with ST_Transform when the layer's CRS is not\n   * already WGS84. Bypasses GDAL's GeoPackage driver entirely (see\n   * geopackage.ts).\n   */\n  private async _createTableFromGeoPackage(\n    tableName: string,\n    bytes: Uint8Array,\n    options: IngestOptions,\n  ): Promise<void> {\n    const { featureCollection, sourceCrs: embeddedSourceCrs } = await readGeoPackage(\n      bytes,\n      options.sourceLayer,\n      this._sqlJsBaseUrl,\n    );\n    const sourceCrs = options.sourceCrs?.trim() || embeddedSourceCrs;\n    // ST_Read of an empty GeoJSON exposes no geometry column, so the EXCLUDE\n    // below would fail; create an empty table with just `geom` instead.\n    if (featureCollection.features.length === 0) {\n      await this._loaded.conn.query(\n        `CREATE OR REPLACE TABLE ${quoteIdent(tableName)} AS ` +\n          `SELECT NULL::GEOMETRY AS geom WHERE false`,\n      );\n      return;\n    }\n    // ST_Read exposes a GeoJSON's geometry as a native GEOMETRY column named\n    // `geom`; reproject it to WGS84 when the GeoPackage stored another CRS so\n    // the rest of the pipeline (tiles, export) can assume EPSG:4326.\n    const geomExpr =\n      sourceCrs == null\n        ? \"geom\"\n        : `ST_Transform(geom, ${quoteLiteral(sourceCrs)}, 'EPSG:4326', always_xy := true)`;\n    // Ingested in batches so neither the JSON document nor the registered\n    // buffer for the whole layer has to exist at once: a half-million-feature\n    // layer otherwise exceeds the maximum JavaScript string length in\n    // JSON.stringify long before it runs out of memory.\n    const batches = sliceFeatureCollection(\n      featureCollection,\n      GEOPACKAGE_INGEST_BATCH,\n    );\n    try {\n      await this._appendGeoPackageBatches(tableName, batches, geomExpr);\n    } catch (error) {\n      // A failure part-way through leaves the table holding the batches that\n      // did land. `ingest` rethrows before registering it in `_tables`, so\n      // `dropTable` could never reach it — drop it here or it leaks for the\n      // lifetime of the connection.\n      await this._loaded.conn\n        .query(`DROP TABLE IF EXISTS ${quoteIdent(tableName)}`)\n        .catch(() => undefined);\n      throw error;\n    }\n  }\n\n  /**\n   * Creates the ingest table from the first batch and appends the rest, so a\n   * large layer never needs its whole GeoJSON document in memory at once.\n   */\n  private async _appendGeoPackageBatches(\n    tableName: string,\n    batches: FeatureCollection<Geometry | null>[],\n    geomExpr: string,\n  ): Promise<void> {\n    for (let index = 0; index < batches.length; index += 1) {\n      const geojsonName = `${tableName}.${index}.geojson`;\n      await this._loaded.db.registerFileBuffer(\n        geojsonName,\n        encodeFeatureCollection(batches[index]),\n      );\n      try {\n        const reader = `ST_Read(${quoteLiteral(geojsonName)})`;\n        const select = `SELECT * EXCLUDE (geom), ${geomExpr} AS geom FROM ${reader}`;\n        // The first batch defines the schema; the rest are matched BY NAME so a\n        // column ST_Read happens to omit from a later batch (an all-null\n        // property, a per-row BLOB the reader drops) fills with NULL instead of\n        // failing on column count.\n        await this._loaded.conn.query(\n          index === 0\n            ? `CREATE OR REPLACE TABLE ${quoteIdent(tableName)} AS ${select}`\n            : `INSERT INTO ${quoteIdent(tableName)} BY NAME ${select}`,\n        );\n      } finally {\n        await this._loaded.db.dropFile(geojsonName).catch(() => undefined);\n      }\n    }\n  }\n\n  /** @inheritdoc */\n  listLayers(\n    source: string | File | Blob,\n    registrationName: string,\n    options: IngestOptions,\n  ): Promise<string[]> {\n    return this._queue.enqueue(async () => {\n      try {\n        // GeoPackages are listed with sql.js, not ST_Read_Meta: GDAL's\n        // GeoPackage driver hangs/crashes on the single-threaded WASM build\n        // (see geopackage.ts).\n        if (options.format === \"geopackage\") {\n          const bytes = await this._geoPackageBytesFor(source);\n          return listGeoPackageLayers(bytes, this._sqlJsBaseUrl);\n        }\n        const path = await this._registerSource(\n          source,\n          registrationName,\n          options,\n        );\n        const result = await this._loaded.conn.query(\n          layersMetaQuery(gdalPath(options.format, path)),\n        );\n        return result.toArray().map((row) => String(row.name));\n      } catch {\n        // Not a GDAL-readable container (or meta unsupported);\n        // treat as single-layer.\n        return [];\n      }\n    });\n  }\n\n  /**\n   * Creates the ingest table from a registered path, normalizing the\n   * geometry column to `geom` and handling CSV WKT/lon-lat layouts.\n   */\n  private async _createTable(\n    tableName: string,\n    path: string,\n    options: IngestOptions,\n  ): Promise<void> {\n    const reader = readerFor(\n      options.format,\n      gdalPath(options.format, path),\n      options.sourceLayer,\n    );\n    const columns = await this._describeReader(reader);\n\n    const geometryColumn = await this._detectGeometryColumn(reader, columns);\n    if (geometryColumn) {\n      // Reproject the source geometry to WGS84 so the rest of the pipeline\n      // (tiles, export) can assume EPSG:4326. A caller override still wins, and\n      // also covers GeoParquet written without usable CRS metadata.\n      const sourceCrs = await this._resolveSourceCrs(\n        path,\n        options,\n        geometryColumn.name,\n      );\n      try {\n        await this._loaded.conn.query(\n          createTableFromGeometrySql(\n            tableName,\n            reader,\n            geometryColumn,\n            sourceCrs,\n          ),\n        );\n      } catch (error) {\n        // DuckDB Spatial's WKB reader rejects surface geometries (TIN /\n        // PolyhedralSurface), which its bundled GDAL emits for ESRI MultiPatch\n        // shapefiles (3D buildings). Re-read the raw WKB and decode it in JS.\n        // Only ST_Read formats can fall back this way (Parquet is read via\n        // read_parquet, not GDAL), so those propagate the original error.\n        if (\n          options.format === \"geoparquet\" ||\n          !isUnsupportedSurfaceWkbError(error)\n        ) {\n          throw error;\n        }\n        await this._createTableFromSurfaceWkb(tableName, path, options);\n      }\n      return;\n    }\n\n    if (options.format === \"csv\") {\n      const lower = new Map(columns.map((c) => [c.name.toLowerCase(), c.name]));\n      const wktName = WKT_COLUMN_NAMES.map((n) => lower.get(n)).find(Boolean);\n      if (wktName) {\n        await this._loaded.conn.query(\n          createTableFromWktSql(tableName, reader, wktName, options.sourceCrs?.trim() || null),\n        );\n        return;\n      }\n      for (const [lon, lat] of LON_LAT_COLUMN_PAIRS) {\n        const lonName = lower.get(lon);\n        const latName = lower.get(lat);\n        if (lonName && latName) {\n          await this._loaded.conn.query(\n            createTableFromLonLatSql(\n              tableName,\n              reader,\n              lonName,\n              latName,\n              options.sourceCrs?.trim() || null,\n            ),\n          );\n          return;\n        }\n      }\n      throw new Error(\n        \"CSV has no recognizable geometry: expected a WKT column \" +\n          `(${WKT_COLUMN_NAMES.join(\", \")}) or longitude/latitude columns`,\n      );\n    }\n\n    throw new Error(\n      `No geometry column found in source (format: ${options.format})`,\n    );\n  }\n\n  /**\n   * Creates the ingest table for a source whose geometry DuckDB Spatial cannot\n   * materialize as a GEOMETRY value — TIN / PolyhedralSurface surfaces, the\n   * encoding GDAL emits for ESRI MultiPatch shapefiles (3D buildings). The\n   * geometry is re-read as raw WKB (`keep_wkb := true`), decoded to a\n   * MultiPolygon in JS, then loaded back through DuckDB's GeoJSON reader (which\n   * accepts the decoded MultiPolygon) and reprojected to WGS84 so the rest of\n   * the pipeline (tiles, export) can assume EPSG:4326.\n   */\n  private async _createTableFromSurfaceWkb(\n    tableName: string,\n    path: string,\n    options: IngestOptions,\n  ): Promise<void> {\n    const wkbReader = keepWkbReaderFor(path, options.sourceLayer);\n    const columns = await this._describeReader(wkbReader);\n    // `keep_wkb` materializes the geometry as a WKB blob column named\n    // `wkb_geometry` (its DuckDB type varies by build: `BLOB` or `WKB_BLOB`), so\n    // find it by that name, falling back to any WKB/BLOB-typed column.\n    const wkbColumn =\n      columns.find((column) => column.name.toLowerCase() === \"wkb_geometry\") ??\n      columns.find((column) => /WKB|BLOB|BINARY/i.test(column.type));\n    if (!wkbColumn) {\n      throw new Error(\"No WKB geometry column found after re-reading raw WKB.\");\n    }\n    const result = await this._loaded.conn.query(`SELECT * FROM ${wkbReader}`);\n    const rows = result.toArray().map((row) => row as Record<string, unknown>);\n    const featureCollection = wkbRowsToFeatureCollection(rows, wkbColumn.name);\n    const sourceCrs =\n      options.sourceCrs?.trim() ||\n      (await this._readSourceCrs(\n        gdalPath(options.format, path),\n        await this._prjWkt(options, path),\n      ));\n\n    const geojsonName = `${tableName}.surface.geojson`;\n    await this._loaded.db.registerFileBuffer(\n      geojsonName,\n      encodeFeatureCollection(featureCollection),\n    );\n    try {\n      const reader = `ST_Read(${quoteLiteral(geojsonName)})`;\n      // The decoded geometry is in the file's own CRS; reproject to WGS84 when a\n      // source CRS was resolved (a `crs`-less GeoJSON reader leaves `geom` in the\n      // source coordinates otherwise).\n      const geomExpr = sourceCrs\n        ? `ST_Transform(geom, ${quoteLiteral(sourceCrs)}, 'EPSG:4326', always_xy := true)`\n        : \"geom\";\n      await this._loaded.conn.query(\n        `CREATE OR REPLACE TABLE ${quoteIdent(tableName)} AS ` +\n          `SELECT * EXCLUDE (geom), ${geomExpr} AS geom FROM ${reader}`,\n      );\n    } finally {\n      await this._loaded.db.dropFile(geojsonName).catch(() => undefined);\n    }\n  }\n\n  /**\n   * The CRS to reproject a source from: the caller's `sourceCrs` override when\n   * given, otherwise whatever the file itself declares.\n   *\n   * GeoParquet declares it in its own `geo` file metadata rather than through\n   * GDAL, because it is read with `read_parquet`; every other format is read\n   * with `ST_Read`, so `ST_Read_Meta` (or a shapefile `.prj`) reports it.\n   *\n   * @param path - Registered file name the source was read from\n   * @param options - The ingest options, whose `sourceCrs` override wins\n   * @param geometryColumn - The geometry column being read, so a GeoParquet\n   *   holding several of them in different CRSs resolves the right one\n   * @returns A CRS `ST_Transform` accepts, or null to skip reprojection\n   */\n  private async _resolveSourceCrs(\n    path: string,\n    options: IngestOptions,\n    geometryColumn?: string,\n  ): Promise<string | null> {\n    const override = options.sourceCrs?.trim();\n    if (override) return override;\n    if (options.format === \"geoparquet\") {\n      return this._readGeoParquetCrs(path, geometryColumn);\n    }\n    return this._readSourceCrs(\n      gdalPath(options.format, path),\n      await this._prjWkt(options, path),\n    );\n  }\n\n  /**\n   * The CRS a GeoParquet file declares in its `geo` file metadata, or null when\n   * it carries none, declares WGS84, or the metadata cannot be read.\n   *\n   * A read failure is swallowed the way {@link _readSourceCrs} swallows one: the\n   * common case is a plain Parquet with no `geo` key at all, and a file whose\n   * coordinates are already lon/lat must still ingest.\n   *\n   * @param path - Registered file name or URL of the Parquet source\n   * @param geometryColumn - The geometry column being read, so a file holding\n   *   several of them in different CRSs resolves the right one\n   * @returns A CRS `ST_Transform` accepts, or null to skip reprojection\n   */\n  private async _readGeoParquetCrs(\n    path: string,\n    geometryColumn?: string,\n  ): Promise<string | null> {\n    try {\n      const result = await this._loaded.conn.query(geoParquetCrsQuery(path));\n      const row = result.toArray()[0] as Record<string, unknown> | undefined;\n      const metadata = row?.[GEOPARQUET_METADATA_COLUMN];\n      return geoParquetSourceCrs(\n        typeof metadata === \"string\" ? metadata : null,\n        isWgs84AuthCrs,\n        geometryColumn,\n      );\n    } catch {\n      return null;\n    }\n  }\n\n  /**\n   * Resolves a source's CRS as a string `ST_Transform` accepts —\n   * `AUTHORITY:CODE` when GDAL identified one, otherwise the raw WKT definition\n   * (common for ESRI `.prj` files without an EPSG code), or null when the source\n   * is already WGS84 or carries no usable CRS (so reprojection is skipped).\n   *\n   * `ST_Read_Meta` is tried first; when it cannot report the CRS the shapefile's\n   * `.prj` sidecar (`prjWkt`) is the fallback. Some duckdb-wasm GDAL/PROJ builds\n   * throw \"cannot be formatted as WKT1 TOWGS84 parameters\" for a datum whose\n   * transform to WGS84 is grid-based rather than a 7-parameter shift (e.g.\n   * OSGB36 / EPSG:27700), which fails the whole metadata query — the `.prj` text\n   * still lets such a layer reproject.\n   *\n   * @param path - Registered file name the ST_Read_Meta query targets\n   * @param prjWkt - The shapefile `.prj` sidecar WKT, or null when absent\n   */\n  private async _readSourceCrs(\n    path: string,\n    prjWkt: string | null = null,\n  ): Promise<string | null> {\n    try {\n      const result = await this._loaded.conn.query(sourceCrsMetaQuery(path));\n      const row = result.toArray()[0] as\n        | { auth_name?: unknown; auth_code?: unknown; wkt?: unknown }\n        | undefined;\n      if (row) {\n        const authName =\n          typeof row.auth_name === \"string\" ? row.auth_name.trim() : \"\";\n        const authCode =\n          row.auth_code != null ? String(row.auth_code).trim() : \"\";\n        if (authName && authCode) {\n          const crs = `${authName.toUpperCase()}:${authCode}`;\n          return isWgs84AuthCrs(crs) ? null : crs;\n        }\n        const wkt = typeof row.wkt === \"string\" ? row.wkt.trim() : \"\";\n        if (wkt) return wkt;\n      }\n      // ST_Read_Meta reported no CRS: fall back to the `.prj` sidecar.\n      return prjWkt?.trim() || null;\n    } catch {\n      // ST_Read_Meta could not materialize the CRS (see the OSGB36 note above).\n      // The `.prj` sidecar still carries it; reprojection is otherwise skipped\n      // and the layer loads in its source coordinates rather than failing.\n      return prjWkt?.trim() || null;\n    }\n  }\n\n  /**\n   * The WKT text of a loose shapefile's `.prj` sidecar, read from\n   * `options.companionFiles`, or null when this is not a shapefile with a\n   * `.prj`. Used as the CRS fallback when `ST_Read_Meta` cannot report it.\n   */\n  private async _prjCompanionWkt(\n    options: IngestOptions,\n  ): Promise<string | null> {\n    if (options.format !== \"shapefile\" || !options.companionFiles?.length) {\n      return null;\n    }\n    const prj = options.companionFiles.find((file) =>\n      file.name.toLowerCase().endsWith(\".prj\"),\n    );\n    if (!prj) return null;\n    const text = (await prj.text()).trim();\n    return text || null;\n  }\n\n  /**\n   * The shapefile `.prj` WKT for the reprojection fallback: the loose\n   * `companionFiles` sidecar, or the `.prj` remembered from a zipped shapefile\n   * (keyed by its registered `.shp` path), or null when there is none.\n   */\n  private async _prjWkt(\n    options: IngestOptions,\n    path: string,\n  ): Promise<string | null> {\n    return (\n      (await this._prjCompanionWkt(options)) ??\n      this._prjWktByPath.get(path) ??\n      null\n    );\n  }\n\n  /**\n   * Creates a streaming view over a GeoParquet reader instead of\n   * materializing the data.\n   *\n   * @returns The CRS the view reprojects from, or null when it reprojects\n   *   nothing -- the caller needs this to decide whether the file's covering\n   *   bbox column is still comparable with WGS84 tile bounds.\n   */\n  private async _createStreamView(\n    tableName: string,\n    path: string,\n    options: IngestOptions,\n  ): Promise<string | null> {\n    const reader = readerFor(options.format, path, options.sourceLayer);\n    const columns = await this._describeReader(reader);\n    const geometryColumn = await this._detectGeometryColumn(reader, columns);\n    if (!geometryColumn) {\n      throw new Error(\"No geometry column found in GeoParquet source\");\n    }\n    const sourceCrs = await this._resolveSourceCrs(\n      path,\n      options,\n      geometryColumn.name,\n    );\n    await this._loaded.conn.query(\n      createViewFromGeometrySql(tableName, reader, geometryColumn, sourceCrs),\n    );\n    return sourceCrs;\n  }\n\n  private async _detectGeometryColumn(\n    reader: string,\n    columns: ColumnInfo[],\n  ): Promise<DetectedGeometryColumn | undefined> {\n    const geometryColumn = detectGeometryColumn(columns);\n    if (!geometryColumn?.requiresBase64WkbValidation) return geometryColumn;\n    const candidates = geometryColumn.base64WkbCandidates?.length\n      ? geometryColumn.base64WkbCandidates\n      : [geometryColumn.name];\n    for (const name of candidates) {\n      if (await this._hasValidBase64WkbValues(reader, name)) {\n        return { name, encoding: geometryColumn.encoding };\n      }\n    }\n    return undefined;\n  }\n\n  private async _hasValidBase64WkbValues(\n    reader: string,\n    column: string,\n  ): Promise<boolean> {\n    const columnSql = quoteIdent(column);\n    const sampleColumn = quoteIdent(\"__maplibre_gl_vector_base64_wkb_sample\");\n    const result = await this._loaded.conn.query(\n      `SELECT count(*) AS sample_count, ` +\n        `count(TRY(ST_GeomFromWKB(from_base64(${sampleColumn})))) AS valid_count ` +\n        `FROM (SELECT ${columnSql} AS ${sampleColumn} FROM ${reader} ` +\n        `WHERE ${columnSql} IS NOT NULL LIMIT 20) AS sample`,\n    );\n    const row = result.toArray()[0] ?? {};\n    const sampleCount = numberFromCount(row.sample_count);\n    const validCount = numberFromCount(row.valid_count);\n    return sampleCount > 0 && sampleCount === validCount;\n  }\n\n  /**\n   * Retries table creation through an object URL when reading a\n   * registered buffer failed (older builds cannot ST_Read virtual\n   * files).\n   *\n   * @returns True when the retry succeeded\n   */\n  private async _retryWithObjectUrl(\n    _error: unknown,\n    source: string | File | Blob,\n    tableName: string,\n    options: IngestOptions,\n    meta: TableMeta,\n  ): Promise<boolean> {\n    if (typeof source === \"string\" || !(source instanceof Blob)) return false;\n    if (options.format === \"geoparquet\" || options.format === \"csv\")\n      return false;\n\n    const objectUrl = URL.createObjectURL(source);\n    try {\n      await this._createTable(tableName, objectUrl, options);\n      meta.objectUrl = objectUrl;\n      return true;\n    } catch {\n      URL.revokeObjectURL(objectUrl);\n      return false;\n    }\n  }\n\n  /**\n   * Describes the columns a reader expression produces.\n   */\n  private async _describeReader(reader: string): Promise<ColumnInfo[]> {\n    const result = await this._loaded.conn.query(\n      columnsQueryFromDescribe(reader),\n    );\n    return result.toArray().map((row) => ({\n      name: String(row.column_name),\n      type: String(row.column_type),\n    }));\n  }\n\n  /**\n   * Describes the columns of an existing table.\n   */\n  private async _describeTable(tableName: string): Promise<ColumnInfo[]> {\n    return this._describeReader(quoteIdent(tableName));\n  }\n\n  /**\n   * Computes feature count, extent, and geometry category of a table.\n   */\n  private async _summarize(\n    tableName: string,\n    meta: TableMeta,\n  ): Promise<Omit<IngestSummary, \"tableName\" | \"byteSize\">> {\n    // Streamed sources with a bbox covering column summarize from the\n    // bbox stats instead of scanning every geometry.\n    const summarySql =\n      meta.streamed && meta.bboxColumn\n        ? bboxSummaryQuery(tableName, meta.bboxColumn)\n        : summaryQuery(tableName);\n    const summaryResult = await this._loaded.conn.query(summarySql);\n    const row = summaryResult.toArray()[0] ?? {};\n    const featureCount = Number(row.feature_count ?? 0);\n\n    let bbox: Bbox | undefined;\n    const coords = [row.xmin, row.ymin, row.xmax, row.ymax].map((v) =>\n      Number(v),\n    );\n    if (coords.every((v) => Number.isFinite(v))) {\n      bbox = coords as Bbox;\n    }\n\n    let geometryType: GeometryCategory = \"unknown\";\n    const typesSql = meta.streamed\n      ? sampledGeometryTypesQuery(tableName)\n      : geometryTypesQuery(tableName);\n    const typesResult = await this._loaded.conn.query(typesSql);\n    for (const typeRow of typesResult.toArray()) {\n      geometryType = mergeGeometryCategory(\n        geometryType === \"unknown\" ? undefined : geometryType,\n        categoryFromTypeName(String(typeRow.geometry_type)),\n      );\n    }\n\n    return { featureCount, bbox, geometryType };\n  }\n\n  private _requireTable(tableName: string): TableMeta {\n    const meta = this._tables.get(tableName);\n    if (!meta) {\n      throw new Error(`Unknown table: ${tableName}`);\n    }\n    return meta;\n  }\n}\n\n/**\n * Loads DuckDB-WASM from the CDN and creates the engine.\n *\n * @param options - Engine creation options\n * @returns The ready engine\n */\nexport async function createEngine(\n  options?: CreateEngineOptions,\n): Promise<IEngine> {\n  const loaded = await loadDuckDB(\n    options?.onProgress,\n    options?.baseUrl,\n    options?.spatialExtensionPath,\n  );\n  options?.onProgress?.(`DuckDB ${loaded.version} ready`);\n  return new DuckDBEngine(loaded, options?.sqlJsBaseUrl);\n}\n","import type { VectorLayerInfo, VectorLayerStyle } from '../core/types';\nimport { el } from './dom';\n\n/**\n * Callbacks for style editor interactions.\n */\nexport interface StyleEditorCallbacks {\n  /** Called when a style value changes */\n  onStyle: (patch: Partial<VectorLayerStyle>) => void;\n  /** Called when the render mode select changes */\n  onRenderMode: (mode: 'auto' | 'geojson' | 'tiles') => void;\n  /** Called when the attribute popup toggle changes */\n  onPicker: (enabled: boolean) => void;\n  /** Called when the before-layer select changes */\n  onBeforeId: (beforeId: string | undefined) => void;\n}\n\n/**\n * Extra context for the style editor.\n */\nexport interface StyleEditorContext {\n  /** Map layer ids the layer can be inserted before */\n  beforeChoices: string[];\n}\n\nfunction colorRow(\n  label: string,\n  value: string,\n  onChange: (value: string) => void,\n): HTMLElement {\n  const row = el('label', 'vector-control-style-row');\n  const text = el('span', 'vector-control-style-label');\n  text.textContent = label;\n  const input = el('input', 'vector-control-color') as HTMLInputElement;\n  input.type = 'color';\n  input.value = value;\n  input.addEventListener('input', () => onChange(input.value));\n  row.appendChild(text);\n  row.appendChild(input);\n  return row;\n}\n\nfunction numberRow(\n  label: string,\n  value: number,\n  opts: { min: number; max: number; step: number },\n  onChange: (value: number) => void,\n): HTMLElement {\n  const row = el('label', 'vector-control-style-row');\n  const text = el('span', 'vector-control-style-label');\n  text.textContent = label;\n  const input = el('input', 'vector-control-range') as HTMLInputElement;\n  input.type = 'range';\n  input.min = String(opts.min);\n  input.max = String(opts.max);\n  input.step = String(opts.step);\n  input.value = String(value);\n  const display = el('span', 'vector-control-range-value');\n  display.textContent = String(value);\n  input.addEventListener('input', () => {\n    display.textContent = input.value;\n    onChange(Number(input.value));\n  });\n  row.appendChild(text);\n  row.appendChild(input);\n  row.appendChild(display);\n  return row;\n}\n\n/**\n * Builds the per-layer style editor (colors, widths, opacity, and the\n * render mode selector).\n *\n * @param layer - The layer being edited\n * @param callbacks - Interaction callbacks\n * @returns The editor element\n */\nexport function createStyleEditor(\n  layer: VectorLayerInfo,\n  context: StyleEditorContext,\n  callbacks: StyleEditorCallbacks,\n): HTMLElement {\n  const editor = el('div', 'vector-control-style-editor');\n  const { style, geometryType } = layer;\n  const showFill = geometryType === 'polygon' || geometryType === 'mixed' || geometryType === 'unknown';\n  const showLine = geometryType !== 'point';\n  const showCircle = geometryType === 'point' || geometryType === 'mixed' || geometryType === 'unknown';\n\n  if (showFill) {\n    editor.appendChild(colorRow('Fill', style.fillColor, (fillColor) => callbacks.onStyle({ fillColor })));\n    editor.appendChild(\n      numberRow('Opacity', style.fillOpacity, { min: 0, max: 1, step: 0.05 }, (fillOpacity) =>\n        callbacks.onStyle({ fillOpacity }),\n      ),\n    );\n  }\n  if (showLine) {\n    editor.appendChild(colorRow('Line', style.lineColor, (lineColor) => callbacks.onStyle({ lineColor })));\n    editor.appendChild(\n      numberRow('Width', style.lineWidth, { min: 0, max: 10, step: 0.5 }, (lineWidth) =>\n        callbacks.onStyle({ lineWidth }),\n      ),\n    );\n  }\n  if (showCircle) {\n    editor.appendChild(\n      colorRow('Circle', style.circleColor, (circleColor) => callbacks.onStyle({ circleColor })),\n    );\n    editor.appendChild(\n      numberRow('Radius', style.circleRadius, { min: 1, max: 20, step: 1 }, (circleRadius) =>\n        callbacks.onStyle({ circleRadius }),\n      ),\n    );\n  }\n\n  // Render mode selector\n  const modeRow = el('label', 'vector-control-style-row');\n  const modeLabel = el('span', 'vector-control-style-label');\n  modeLabel.textContent = 'Mode';\n  const select = el('select', 'vector-control-select') as HTMLSelectElement;\n  for (const mode of ['auto', 'geojson', 'tiles'] as const) {\n    const option = el('option') as HTMLOptionElement;\n    option.value = mode;\n    option.textContent = mode === 'geojson' ? 'GeoJSON' : mode === 'tiles' ? 'Tiles' : 'Auto';\n    if (mode === layer.renderMode) option.selected = true;\n    select.appendChild(option);\n  }\n  select.addEventListener('change', () => {\n    callbacks.onRenderMode(select.value as 'auto' | 'geojson' | 'tiles');\n  });\n  modeRow.appendChild(modeLabel);\n  modeRow.appendChild(select);\n  editor.appendChild(modeRow);\n\n  // Attribute popup toggle\n  const pickerRow = el('label', 'vector-control-style-row');\n  const pickerLabel = el('span', 'vector-control-style-label');\n  pickerLabel.textContent = 'Popup';\n  const pickerInput = el('input', 'vector-control-checkbox') as HTMLInputElement;\n  pickerInput.type = 'checkbox';\n  pickerInput.checked = layer.picker;\n  pickerInput.addEventListener('change', () => callbacks.onPicker(pickerInput.checked));\n  pickerRow.appendChild(pickerLabel);\n  pickerRow.appendChild(pickerInput);\n  editor.appendChild(pickerRow);\n\n  // Insert-before layer selector\n  const beforeRow = el('label', 'vector-control-style-row');\n  const beforeLabel = el('span', 'vector-control-style-label');\n  beforeLabel.textContent = 'Before';\n  const beforeSelect = el('select', 'vector-control-select') as HTMLSelectElement;\n  const topOption = el('option') as HTMLOptionElement;\n  topOption.value = '';\n  topOption.textContent = '(top)';\n  beforeSelect.appendChild(topOption);\n  for (const choice of context.beforeChoices) {\n    const option = el('option') as HTMLOptionElement;\n    option.value = choice;\n    option.textContent = choice;\n    if (choice === layer.beforeId) option.selected = true;\n    beforeSelect.appendChild(option);\n  }\n  beforeSelect.addEventListener('change', () =>\n    callbacks.onBeforeId(beforeSelect.value || undefined),\n  );\n  beforeRow.appendChild(beforeLabel);\n  beforeRow.appendChild(beforeSelect);\n  editor.appendChild(beforeRow);\n\n  return editor;\n}\n","import type { VectorLayerInfo, VectorLayerStyle } from '../core/types';\nimport { el, svgIcon, ICONS } from './dom';\nimport { createStyleEditor, type StyleEditorContext } from './styleEditor';\n\n/**\n * Callbacks for layer list item interactions.\n */\nexport interface LayerItemCallbacks {\n  onToggleVisibility: (id: string, visible: boolean) => void;\n  onZoom: (id: string) => void;\n  onRemove: (id: string) => void;\n  onStyle: (id: string, patch: Partial<VectorLayerStyle>) => void;\n  onRenderMode: (id: string, mode: 'auto' | 'geojson' | 'tiles') => void;\n  onPicker: (id: string, enabled: boolean) => void;\n  onBeforeId: (id: string, beforeId: string | undefined) => void;\n  /** Toggles the expanded state of the style editor */\n  onToggleEditor: (id: string) => void;\n}\n\nfunction iconButton(title: string, paths: string, onClick: () => void): HTMLButtonElement {\n  const button = el('button', 'vector-control-icon-btn', { type: 'button', title });\n  button.setAttribute('aria-label', title);\n  button.appendChild(svgIcon(paths));\n  button.addEventListener('click', (e) => {\n    e.stopPropagation();\n    onClick();\n  });\n  return button;\n}\n\nfunction formatCount(count: number): string {\n  if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1)}M`;\n  if (count >= 1_000) return `${(count / 1_000).toFixed(1)}k`;\n  return String(count);\n}\n\n/**\n * Builds a single row in the layer list, with visibility, zoom, style,\n * and remove actions plus an optional expanded style editor.\n *\n * @param layer - The layer to render\n * @param expanded - Whether the style editor is expanded\n * @param callbacks - Interaction callbacks\n * @returns The list item element\n */\nexport function createLayerListItem(\n  layer: VectorLayerInfo,\n  expanded: boolean,\n  context: StyleEditorContext,\n  callbacks: LayerItemCallbacks,\n): HTMLElement {\n  const item = el('div', 'vector-control-layer-item');\n  item.dataset.layerId = layer.id;\n\n  const row = el('div', 'vector-control-layer-row');\n\n  // Visibility toggle\n  row.appendChild(\n    iconButton(\n      layer.visible ? 'Hide layer' : 'Show layer',\n      layer.visible ? ICONS.eye : ICONS.eyeOff,\n      () => callbacks.onToggleVisibility(layer.id, !layer.visible),\n    ),\n  );\n\n  // Name and meta\n  const nameWrap = el('div', 'vector-control-layer-name-wrap');\n  const name = el('div', 'vector-control-layer-name', { title: layer.name });\n  name.textContent = layer.name;\n  const meta = el('div', 'vector-control-layer-meta');\n  const parts: string[] = [layer.format];\n  if (layer.featureCount !== undefined) parts.push(`${formatCount(layer.featureCount)} ft`);\n  parts.push(layer.renderMode === 'tiles' ? 'tiles' : 'geojson');\n  if (layer.ingestMode === 'stream') parts.push('stream');\n  meta.textContent = parts.join(' · ');\n  nameWrap.appendChild(name);\n  nameWrap.appendChild(meta);\n  nameWrap.addEventListener('click', () => callbacks.onToggleEditor(layer.id));\n  row.appendChild(nameWrap);\n\n  // Actions\n  const actions = el('div', 'vector-control-layer-actions');\n  actions.appendChild(iconButton('Zoom to layer', ICONS.zoom, () => callbacks.onZoom(layer.id)));\n  actions.appendChild(\n    iconButton('Layer style', ICONS.sliders, () => callbacks.onToggleEditor(layer.id)),\n  );\n  actions.appendChild(iconButton('Remove layer', ICONS.trash, () => callbacks.onRemove(layer.id)));\n  row.appendChild(actions);\n\n  item.appendChild(row);\n\n  if (expanded) {\n    item.appendChild(\n      createStyleEditor(layer, context, {\n        onStyle: (patch) => callbacks.onStyle(layer.id, patch),\n        onRenderMode: (mode) => callbacks.onRenderMode(layer.id, mode),\n        onPicker: (enabled) => callbacks.onPicker(layer.id, enabled),\n        onBeforeId: (beforeId) => callbacks.onBeforeId(layer.id, beforeId),\n      }),\n    );\n  }\n\n  return item;\n}\n","import type { Map as MapLibreMap } from 'maplibre-gl';\nimport type {\n  RenderMode,\n  VectorControlEvent,\n  VectorControlEventHandler,\n  VectorDataSource,\n  VectorFileOpener,\n  VectorFileSelection,\n  VectorLayerInfo,\n  VectorLayerOptions,\n  VectorLayerStyle,\n  VectorSampleDataset,\n} from '../core/types';\nimport { el, svgIcon, ICONS } from './dom';\nimport { createLayerListItem } from './layerListItem';\nimport { groupShapefileComponents } from '../formats/shapefile';\n\n/**\n * The control surface the panel UI talks to. `VectorControl` satisfies\n * this structurally; the interface avoids a circular import.\n */\nexport interface PanelHost {\n  addData(source: VectorDataSource, options?: VectorLayerOptions): Promise<VectorLayerInfo>;\n  removeLayer(id: string): void;\n  getLayers(): VectorLayerInfo[];\n  setLayerVisibility(id: string, visible: boolean): void;\n  zoomToLayer(id: string): void;\n  setLayerStyle(id: string, style: Partial<VectorLayerStyle>): void;\n  setLayerPicker(id: string, enabled: boolean): void;\n  setLayerBeforeId(id: string, beforeId?: string): void;\n  setRenderMode(id: string, mode: RenderMode): Promise<void>;\n  getMap(): MapLibreMap | undefined;\n  on(event: VectorControlEvent, handler: VectorControlEventHandler): void;\n  off(event: VectorControlEvent, handler: VectorControlEventHandler): void;\n}\n\n/**\n * Options for rendering the panel UI.\n */\nexport interface PanelUIOptions {\n  /** The panel content element to render into */\n  container: HTMLElement;\n  /** The owning control */\n  control: PanelHost;\n  /** Placeholder text for the URL input */\n  urlPlaceholder?: string;\n  /** Initial value of the URL input (cleared after a successful load) */\n  defaultUrl?: string;\n  /** Load defaultUrl immediately, as if the user had pressed Load */\n  autoLoad?: boolean;\n  /** One-click sample datasets shown below the URL input (row hidden when empty) */\n  sampleData?: VectorSampleDataset[];\n  /** Label shown before the sample links (defaults to 'Load sample data:') */\n  sampleDataLabel?: string;\n  /**\n   * Host-supplied file picker. When set, clicking the drop zone calls this\n   * instead of the native file input, and each returned selection is loaded\n   * with its `sourcePath` recorded on the layer (see\n   * {@link VectorControlOptions.fileOpener}).\n   */\n  fileOpener?: VectorFileOpener;\n}\n\n/**\n * Renders the vector control panel UI (file/URL loading, status line,\n * and the layer list) and wires it to the control.\n *\n * @param options - Panel options\n * @returns A dispose function that unsubscribes event handlers\n */\nexport function renderPanelUI(options: PanelUIOptions): () => void {\n  const { container, control, fileOpener } = options;\n  const expandedEditors = new Set<string>();\n  let styleEditInProgress = false;\n  let selectedSample: VectorSampleDataset | null = null;\n\n  container.innerHTML = '';\n\n  // --- Drop zone / file picker -----------------------------------------\n  const dropZone = el('div', 'vector-control-dropzone');\n  dropZone.appendChild(svgIcon(ICONS.upload, 18));\n  const dropText = el('span');\n  dropText.textContent = 'Drop file or click to browse';\n  dropZone.appendChild(dropText);\n\n  // No accept filter: every format the spatial extension's GDAL build\n  // can read (kml, gml, tab, dxf, ...) is fair game, not just the\n  // extensions with dedicated readers.\n  const fileInput = el('input') as HTMLInputElement;\n  fileInput.type = 'file';\n  fileInput.multiple = true;\n  fileInput.style.display = 'none';\n\n  // A host can replace the native browse with its own picker (e.g. a desktop\n  // dialog that yields real filesystem paths). Drag-and-drop still uses the\n  // browser's dropped files, which carry no path.\n  dropZone.addEventListener('click', () => {\n    if (fileOpener) {\n      void openViaHost();\n    } else {\n      fileInput.click();\n    }\n  });\n  dropZone.addEventListener('dragover', (e) => {\n    e.preventDefault();\n    dropZone.classList.add('dragover');\n  });\n  dropZone.addEventListener('dragleave', () => dropZone.classList.remove('dragover'));\n  dropZone.addEventListener('drop', (e) => {\n    e.preventDefault();\n    dropZone.classList.remove('dragover');\n    const files = e.dataTransfer?.files;\n    if (files) loadFiles(files);\n  });\n  fileInput.addEventListener('change', () => {\n    if (fileInput.files) loadFiles(fileInput.files);\n    fileInput.value = '';\n  });\n\n  // --- URL input ---------------------------------------------------------\n  const urlRow = el('div', 'vector-control-flex vector-control-url-row');\n  const urlInput = el('input', 'vector-control-input') as HTMLInputElement;\n  urlInput.type = 'url';\n  urlInput.placeholder = options.urlPlaceholder ?? 'https://example.com/data.parquet';\n  if (options.defaultUrl) urlInput.value = options.defaultUrl;\n  const urlButton = el('button', 'vector-control-button', { type: 'button' });\n  urlButton.textContent = 'Load';\n  const loadUrl = () => {\n    const url = urlInput.value.trim();\n    if (!url) return;\n    const loadSample =\n      selectedSample && selectedSample.url === url ? selectedSample : null;\n    void control.addData(url, loadSample ? sampleLoadOptions(loadSample) : loadOptions()).then(\n      () => {\n        urlInput.value = '';\n        selectedSample = null;\n      },\n      () => {\n        // Error already surfaced through the 'error' event.\n      },\n    );\n  };\n  urlButton.addEventListener('click', loadUrl);\n  urlInput.addEventListener('keydown', (e) => {\n    if (e.key === 'Enter') loadUrl();\n  });\n  urlInput.addEventListener('input', () => {\n    if (selectedSample && urlInput.value.trim() !== selectedSample.url) {\n      selectedSample = null;\n    }\n  });\n  urlRow.appendChild(urlInput);\n  urlRow.appendChild(urlButton);\n\n  // --- Sample data dropdown ------------------------------------------------\n  // A custom (not native <select>) dropdown so the menu is fully themeable\n  // in dark mode -- the native option popup keeps a low-contrast system\n  // highlight. Decoupled from the URL input so it stays empty for the\n  // user's own links; picking one fills the input, leaving loading to the\n  // explicit Load button. Hidden\n  // entirely when no host supplies samples.\n  const samples = options.sampleData ?? [];\n  const sampleRow = el('div', 'vector-control-sample-row');\n  let onSampleDocPointerDown: ((event: MouseEvent) => void) | null = null;\n  if (samples.length > 0) {\n    const trigger = el('button', 'vector-control-sample-trigger', {\n      type: 'button',\n      'aria-haspopup': 'listbox',\n      'aria-expanded': 'false',\n    });\n    const triggerLabel = el('span', 'vector-control-sample-trigger-label');\n    triggerLabel.textContent = options.sampleDataLabel ?? 'Load sample data...';\n    trigger.appendChild(triggerLabel);\n    trigger.appendChild(svgIcon(ICONS.chevronDown, 14));\n\n    const menu = el('div', 'vector-control-sample-menu', { role: 'listbox' });\n    menu.hidden = true;\n\n    let menuOpen = false;\n    const setMenuOpen = (open: boolean): void => {\n      menuOpen = open;\n      menu.hidden = !open;\n      trigger.setAttribute('aria-expanded', String(open));\n      trigger.classList.toggle('open', open);\n      if (open) (menu.firstElementChild as HTMLElement | null)?.focus();\n    };\n\n    for (const sample of samples) {\n      const option = el('button', 'vector-control-sample-option', {\n        type: 'button',\n        role: 'option',\n        title: sample.url,\n      });\n      option.textContent = sample.label;\n      option.addEventListener('click', () => {\n        setMenuOpen(false);\n        trigger.focus();\n        // Show the user which URL will load when they explicitly confirm.\n        urlInput.value = sample.url;\n        selectedSample = sample;\n      });\n      menu.appendChild(option);\n    }\n\n    trigger.addEventListener('click', () => setMenuOpen(!menuOpen));\n    sampleRow.addEventListener('keydown', (event) => {\n      if ((event as KeyboardEvent).key === 'Escape' && menuOpen) {\n        setMenuOpen(false);\n        trigger.focus();\n      }\n    });\n\n    // Close when clicking anywhere outside the dropdown.\n    onSampleDocPointerDown = (event: MouseEvent) => {\n      if (!sampleRow.contains(event.target as Node)) setMenuOpen(false);\n    };\n    document.addEventListener('pointerdown', onSampleDocPointerDown);\n\n    sampleRow.appendChild(trigger);\n    sampleRow.appendChild(menu);\n  }\n\n  // --- Streaming toggle ----------------------------------------------------\n  // Applies to subsequent loads; GeoParquet only (others fall back to\n  // a materialized table).\n  const streamRow = el('label', 'vector-control-stream-row', {\n    title:\n      'Query GeoParquet in place with HTTP range requests instead of copying it into DuckDB. ' +\n      'Best for large remote files with a bbox covering column.',\n  });\n  const streamInput = el('input', 'vector-control-checkbox') as HTMLInputElement;\n  streamInput.type = 'checkbox';\n  const streamText = el('span');\n  streamText.textContent = 'Stream GeoParquet (no copy)';\n  streamRow.appendChild(streamInput);\n  streamRow.appendChild(streamText);\n\n  // --- Optional source CRS override ---------------------------------------\n  // Some producers write projected coordinates but omit GeoParquet's `crs`\n  // metadata. Let the user state what those coordinates mean rather than\n  // sending impossible latitude values to MapLibre.\n  const sourceCrsInput = el('input', 'vector-control-input') as HTMLInputElement;\n  sourceCrsInput.type = 'text';\n  sourceCrsInput.placeholder = 'Source CRS override (e.g. EPSG:28992)';\n  sourceCrsInput.setAttribute('aria-label', 'Source CRS override');\n\n  // --- Status line ---------------------------------------------------------\n  const status = el('div', 'vector-control-status');\n  status.style.display = 'none';\n\n  function setStatus(message: string | null, isError = false): void {\n    if (!message) {\n      status.style.display = 'none';\n      status.textContent = '';\n      syncScrollbarPadding();\n      return;\n    }\n    status.style.display = 'block';\n    status.textContent = message;\n    status.classList.toggle('error', isError);\n    syncScrollbarPadding();\n  }\n\n  // --- Layer list ------------------------------------------------------------\n  const listTitle = el('div', 'vector-control-section-title');\n  listTitle.textContent = 'Layers';\n  const list = el('div', 'vector-control-layer-list');\n  const empty = el('div', 'vector-control-empty');\n  empty.textContent = 'No layers loaded yet';\n\n  function renderList(): void {\n    const layers = control.getLayers();\n    list.innerHTML = '';\n    if (layers.length === 0) {\n      list.appendChild(empty);\n      syncScrollbarPadding();\n      return;\n    }\n    // Map layers this control did not create, as insert-before targets\n    const ownLayerIds = new Set(layers.flatMap((layer) => layer.layerIds));\n    const beforeChoices = (control.getMap()?.getStyle()?.layers ?? [])\n      .map((mapLayer) => mapLayer.id)\n      .filter((mapLayerId) => !ownLayerIds.has(mapLayerId));\n    for (const layer of layers) {\n      list.appendChild(\n        createLayerListItem(layer, expandedEditors.has(layer.id), { beforeChoices }, {\n          onToggleVisibility: (id, visible) => control.setLayerVisibility(id, visible),\n          onZoom: (id) => control.zoomToLayer(id),\n          onRemove: (id) => {\n            expandedEditors.delete(id);\n            control.removeLayer(id);\n          },\n          onStyle: (id, patch) => {\n            // Avoid re-rendering the list mid color-drag (focus loss).\n            styleEditInProgress = true;\n            try {\n              control.setLayerStyle(id, patch);\n            } finally {\n              styleEditInProgress = false;\n            }\n          },\n          onRenderMode: (id, mode) => {\n            void control.setRenderMode(id, mode).catch(() => {\n              // Error already surfaced through the 'error' event.\n            });\n          },\n          onPicker: (id, enabled) => control.setLayerPicker(id, enabled),\n          onBeforeId: (id, beforeId) => control.setLayerBeforeId(id, beforeId),\n          onToggleEditor: (id) => {\n            if (expandedEditors.has(id)) {\n              expandedEditors.delete(id);\n            } else {\n              expandedEditors.add(id);\n            }\n            renderList();\n          },\n        }),\n      );\n    }\n    syncScrollbarPadding();\n  }\n\n  // The panel's scrollbar is an overlay in some engines, so it paints over\n  // the right edge of the inputs/buttons when the content overflows.\n  // Reserve room for it only while overflowing, keeping the left and right\n  // margins symmetric when there is no scrollbar.\n  function syncScrollbarPadding(): void {\n    container.classList.toggle(\n      'vector-control-has-scrollbar',\n      container.scrollHeight > container.clientHeight,\n    );\n  }\n\n  function loadOptions(): VectorLayerOptions {\n    // Explicit 'table' when unchecked, so the toggle wins over a\n    // control-level defaultIngestMode of 'stream'.\n    const sourceCrs = sourceCrsInput.value.trim();\n    return {\n      ingestMode: streamInput.checked ? 'stream' : 'table',\n      ...(sourceCrs ? { sourceCrs } : {}),\n    };\n  }\n\n  function sampleLoadOptions(sample: VectorSampleDataset): VectorLayerOptions {\n    const sampleOptions: VectorLayerOptions = {\n      ...loadOptions(),\n      ...(sample.ingestMode ? { ingestMode: sample.ingestMode } : {}),\n    };\n    if (sample.name) sampleOptions.name = sample.name;\n    if (sample.renderMode) sampleOptions.renderMode = sample.renderMode;\n    return sampleOptions;\n  }\n\n  function loadFiles(files: FileList): void {\n    // Group loose shapefile components selected together so a `.shp` loads with\n    // its `.shx`/`.dbf`/`.prj`/... siblings as one layer, instead of the `.shp`\n    // failing for missing siblings and each sidecar loading as its own layer.\n    for (const { file, companions } of groupShapefileComponents(Array.from(files))) {\n      const options =\n        companions.length > 0\n          ? { ...loadOptions(), companionFiles: companions }\n          : loadOptions();\n      void control.addData(file, options).catch(() => {\n        // Error already surfaced through the 'error' event.\n      });\n    }\n  }\n\n  // Runs the host-supplied picker (when set) and loads its selections, carrying\n  // each file's sourcePath through to addData so a desktop host can persist and\n  // re-read it. Mirrors loadFiles' shapefile grouping; a returned empty list (or\n  // a cancelled picker) loads nothing.\n  async function openViaHost(): Promise<void> {\n    let selections: VectorFileSelection[] | null | undefined;\n    try {\n      selections = await fileOpener?.();\n    } catch (error) {\n      setStatus(error instanceof Error ? error.message : 'Could not open files', true);\n      return;\n    }\n    if (!selections || selections.length === 0) return;\n    loadSelections(selections);\n  }\n\n  function loadSelections(selections: VectorFileSelection[]): void {\n    // Only File instances can be regrouped by name for loose shapefiles; a raw\n    // Blob has no name, so it loads on its own.\n    const files = selections.map((selection) => selection.file);\n    const pathByFile = new Map<File | Blob, string | undefined>(\n      selections.map((selection) => [selection.file, selection.sourcePath]),\n    );\n    const nameByFile = new Map<File | Blob, string | undefined>(\n      selections.map((selection) => [selection.file, selection.name]),\n    );\n    const fileEntries = files.filter((file): file is File => file instanceof File);\n    const blobEntries = files.filter((file) => !(file instanceof File));\n\n    for (const { file, companions } of groupShapefileComponents(fileEntries)) {\n      const options: VectorLayerOptions = {\n        ...loadOptions(),\n        ...(companions.length > 0 ? { companionFiles: companions } : {}),\n        ...(pathByFile.get(file) ? { sourcePath: pathByFile.get(file) } : {}),\n        ...(nameByFile.get(file) ? { name: nameByFile.get(file) } : {}),\n      };\n      void control.addData(file, options).catch(() => {\n        // Error already surfaced through the 'error' event.\n      });\n    }\n    for (const blob of blobEntries) {\n      const options: VectorLayerOptions = {\n        ...loadOptions(),\n        ...(pathByFile.get(blob) ? { sourcePath: pathByFile.get(blob) } : {}),\n        ...(nameByFile.get(blob) ? { name: nameByFile.get(blob) } : {}),\n      };\n      void control.addData(blob, options).catch(() => {\n        // Error already surfaced through the 'error' event.\n      });\n    }\n  }\n\n  // --- Event wiring ---------------------------------------------------------\n  const onLoading: VectorControlEventHandler = (e) => setStatus(e.message ?? 'Loading...');\n  const onError: VectorControlEventHandler = (e) =>\n    setStatus(e.error?.message ?? 'Loading failed', true);\n  const onLayerChange: VectorControlEventHandler = () => {\n    setStatus(null);\n    if (!styleEditInProgress) renderList();\n  };\n\n  control.on('loading', onLoading);\n  control.on('error', onError);\n  control.on('layeradded', onLayerChange);\n  control.on('layerremoved', onLayerChange);\n  control.on('layerupdated', onLayerChange);\n\n  container.appendChild(dropZone);\n  container.appendChild(fileInput);\n  container.appendChild(urlRow);\n  if (samples.length > 0) container.appendChild(sampleRow);\n  container.appendChild(streamRow);\n  container.appendChild(sourceCrsInput);\n  container.appendChild(status);\n  container.appendChild(el('div', 'vector-control-divider'));\n  container.appendChild(listTitle);\n  container.appendChild(list);\n\n  renderList();\n\n  // Resizing the panel changes the content's own height (so the overflow\n  // state can flip) without firing a layer event; a ResizeObserver keeps\n  // the scrollbar padding in sync with those size changes.\n  const scrollObserver =\n    typeof ResizeObserver !== 'undefined'\n      ? new ResizeObserver(() => syncScrollbarPadding())\n      : null;\n  scrollObserver?.observe(container);\n\n  // Kick off the initial load through the same path as the Load button,\n  // so progress/errors surface in the status line and the input clears\n  // on success.\n  if (options.autoLoad && urlInput.value) loadUrl();\n\n  return () => {\n    control.off('loading', onLoading);\n    control.off('error', onError);\n    control.off('layeradded', onLayerChange);\n    control.off('layerremoved', onLayerChange);\n    control.off('layerupdated', onLayerChange);\n    scrollObserver?.disconnect();\n    if (onSampleDocPointerDown) {\n      document.removeEventListener('pointerdown', onSampleDocPointerDown);\n    }\n    container.innerHTML = '';\n  };\n}\n","import type { FeatureCollection } from 'geojson';\nimport type { IControl, Map as MapLibreMap } from 'maplibre-gl';\nimport type {\n  RenderMode,\n  VectorControlEvent,\n  VectorControlEventHandler,\n  VectorControlOptions,\n  VectorDataSource,\n  VectorEventPayload,\n  VectorLayerInfo,\n  VectorLayerOptions,\n  VectorLayerStyle,\n  VectorState,\n} from './types';\nimport { LayerManager } from './LayerManager';\nimport type { IEngine } from '../engine/types';\nimport { createEngine } from '../engine/DuckDBEngine';\nimport { renderPanelUI } from '../ui/panel';\n\n/**\n * Default options for the VectorControl\n */\nconst DEFAULT_OPTIONS: Required<\n  Pick<VectorControlOptions, 'collapsed' | 'position' | 'title' | 'panelWidth' | 'className'>\n> = {\n  collapsed: true,\n  position: 'top-right',\n  title: 'Vector Data',\n  panelWidth: 320,\n  className: '',\n};\n\n/**\n * Event handlers map type\n */\ntype EventHandlersMap = globalThis.Map<VectorControlEvent, Set<VectorControlEventHandler>>;\n\n/**\n * A MapLibre GL control for visualizing vector data in many formats\n * (GeoJSON, GeoPackage, Shapefile, GeoParquet, FlatGeobuf, CSV/WKT).\n *\n * Small datasets are converted to GeoJSON; large datasets are rendered\n * as dynamic MVT tiles generated client-side by DuckDB-WASM and served\n * through a `duckdb://` protocol handler. DuckDB is lazy-loaded from a\n * CDN only when a non-GeoJSON format (or tile rendering) is requested.\n *\n * @example\n * ```typescript\n * const control = new VectorControl({ collapsed: false });\n * map.addControl(control, 'top-right');\n * await control.addData('https://example.com/data.geojson');\n * await control.addData('https://example.com/buildings.parquet');\n * ```\n */\nexport class VectorControl implements IControl {\n  private _map?: MapLibreMap;\n  private _mapContainer?: HTMLElement;\n  private _container?: HTMLElement;\n  private _panel?: HTMLElement;\n  private _content?: HTMLElement;\n  private _options: VectorControlOptions & typeof DEFAULT_OPTIONS;\n  private _state: VectorState;\n  private _eventHandlers: EventHandlersMap = new globalThis.Map();\n  private _layerManager?: LayerManager;\n  private _enginePromise?: Promise<IEngine>;\n  private _disposePanelUI?: () => void;\n  private _styleLoadHandler: (() => void) | null = null;\n  private _styleRestorePromise: Promise<void> = Promise.resolve();\n  private _removed = false;\n\n  // Panel positioning handlers\n  private _resizeHandler: (() => void) | null = null;\n  private _mapResizeHandler: (() => void) | null = null;\n  private _clickOutsideHandler: ((e: MouseEvent) => void) | null = null;\n\n  // User-chosen panel size from the resize handles, reapplied by\n  // _updatePanelPosition so repositioning (map/window resize) keeps it.\n  private _userWidth: number | null = null;\n  private _userHeight: number | null = null;\n  // Active drag teardown, so onRemove can detach mid-resize.\n  private _resizeDragCleanup: (() => void) | null = null;\n\n  /**\n   * Creates a new VectorControl instance.\n   *\n   * @param options - Configuration options for the control\n   */\n  constructor(options?: Partial<VectorControlOptions>) {\n    this._options = { ...DEFAULT_OPTIONS, ...options };\n    this._state = {\n      collapsed: this._options.collapsed,\n      panelWidth: this._options.panelWidth,\n      layers: [],\n      data: {},\n    };\n  }\n\n  /**\n   * Called when the control is added to the map.\n   * Implements the IControl interface.\n   *\n   * @param map - The MapLibre GL map instance\n   * @returns The control's container element\n   */\n  onAdd(map: MapLibreMap): HTMLElement {\n    this._removed = false;\n    this._map = map;\n    this._mapContainer = map.getContainer();\n    this._container = this._createContainer();\n    this._panel = this._createPanel();\n\n    this._layerManager = new LayerManager({\n      map,\n      options: this._options,\n      emit: (type, extra) => this._emit(type, extra),\n      getEngine: () => this._getEngine(),\n    });\n    this._styleLoadHandler = () => {\n      this._styleRestorePromise = this._styleRestorePromise.then(async () => {\n        if (this._removed) return;\n        try {\n          await this._layerManager?.restoreLayersAfterStyleChange();\n        } catch (error: unknown) {\n          const normalized = error instanceof Error ? error : new Error(String(error));\n          this._emit('error', { error: normalized });\n        }\n      });\n    };\n    map.on('style.load', this._styleLoadHandler);\n\n    // Append panel to map container for independent positioning (avoids overlap with other controls)\n    this._mapContainer.appendChild(this._panel);\n\n    // Render the data loading / layer list UI into the panel content area\n    if (this._content) {\n      this._disposePanelUI = renderPanelUI({\n        container: this._content,\n        control: this,\n        urlPlaceholder: this._options.urlPlaceholder,\n        defaultUrl: this._options.defaultUrl,\n        autoLoad: this._options.autoLoad,\n        sampleData: this._options.sampleData,\n        sampleDataLabel: this._options.sampleDataLabel,\n        fileOpener: this._options.fileOpener,\n      });\n    }\n\n    // Setup event listeners for panel positioning and click-outside\n    this._setupEventListeners();\n\n    // Set initial panel state\n    if (!this._state.collapsed) {\n      this._panel.classList.add('expanded');\n      // Update position after control is added to DOM\n      requestAnimationFrame(() => {\n        this._updatePanelPosition();\n      });\n    }\n\n    return this._container;\n  }\n\n  /**\n   * Called when the control is removed from the map.\n   * Implements the IControl interface.\n   */\n  onRemove(): void {\n    this._removed = true;\n    // Remove event listeners\n    if (this._resizeHandler) {\n      window.removeEventListener('resize', this._resizeHandler);\n      this._resizeHandler = null;\n    }\n    if (this._mapResizeHandler && this._map) {\n      this._map.off('resize', this._mapResizeHandler);\n      this._mapResizeHandler = null;\n    }\n    if (this._clickOutsideHandler) {\n      document.removeEventListener('click', this._clickOutsideHandler);\n      this._clickOutsideHandler = null;\n    }\n    // Detach any in-flight resize drag listeners.\n    this._resizeDragCleanup?.();\n    if (this._styleLoadHandler && this._map) {\n      this._map.off('style.load', this._styleLoadHandler);\n      this._styleLoadHandler = null;\n    }\n\n    // Tear down panel UI and layers\n    this._disposePanelUI?.();\n    this._disposePanelUI = undefined;\n    const layerManager = this._layerManager;\n    this._layerManager = undefined;\n\n    // Terminate the DuckDB worker if it was loaded\n    const enginePromise = this._enginePromise;\n    this._enginePromise = undefined;\n    void this._styleRestorePromise.finally(() => {\n      layerManager?.dispose();\n      if (enginePromise) enginePromise.then((engine) => engine.dispose()).catch(() => undefined);\n    });\n\n    // Remove panel from map container\n    this._panel?.parentNode?.removeChild(this._panel);\n\n    // Remove button container from control stack\n    this._container?.parentNode?.removeChild(this._container);\n\n    this._map = undefined;\n    this._mapContainer = undefined;\n    this._container = undefined;\n    this._panel = undefined;\n    this._content = undefined;\n    this._eventHandlers.clear();\n  }\n\n  // ---------------------------------------------------------------------\n  // Data API\n  // ---------------------------------------------------------------------\n\n  /**\n   * Loads a vector data source and adds it to the map.\n   *\n   * @param source - URL string, File/Blob, or GeoJSON object\n   * @param options - Layer options\n   * @returns Metadata of the added layer\n   */\n  async addData(\n    source: VectorDataSource,\n    options?: VectorLayerOptions,\n  ): Promise<VectorLayerInfo> {\n    return this._manager().addData(source, options);\n  }\n\n  /**\n   * Removes a layer added with {@link addData}.\n   *\n   * @param id - The layer id\n   */\n  removeLayer(id: string): void {\n    this._layerManager?.removeLayer(id);\n  }\n\n  /**\n   * Removes all layers added with {@link addData}.\n   */\n  removeAll(): void {\n    this._layerManager?.removeAll();\n  }\n\n  /**\n   * Returns metadata for all loaded layers.\n   */\n  getLayers(): VectorLayerInfo[] {\n    return this._layerManager?.getLayers() ?? [];\n  }\n\n  /**\n   * Returns metadata for a single layer.\n   *\n   * @param id - The layer id\n   */\n  getLayer(id: string): VectorLayerInfo | undefined {\n    return this._layerManager?.getLayer(id);\n  }\n\n  /**\n   * Materializes a layer's features as a GeoJSON FeatureCollection, so a host\n   * can persist the data of a layer loaded from a local file (which a saved\n   * project cannot otherwise recreate). Returns null for an unknown id, or a\n   * layer whose data is not held locally (e.g. a streamed GeoParquet).\n   *\n   * @param id - The layer id.\n   * @returns The features as a FeatureCollection, or null when unavailable.\n   */\n  getLayerGeoJSON(id: string): Promise<FeatureCollection | null> {\n    return this._layerManager?.getLayerGeoJSON(id) ?? Promise.resolve(null);\n  }\n\n  /**\n   * Reads the non-null values of one layer attribute without materializing\n   * engine-backed geometry.\n   *\n   * @param id - The layer id.\n   * @param property - An attribute field name.\n   * @returns The values, or null when the layer or field is unavailable.\n   */\n  getLayerPropertyValues(id: string, property: string): Promise<unknown[] | null> {\n    return this._layerManager?.getLayerPropertyValues(id, property) ?? Promise.resolve(null);\n  }\n\n  /**\n   * Shows or hides a layer.\n   *\n   * @param id - The layer id\n   * @param visible - Whether the layer should be visible\n   */\n  setLayerVisibility(id: string, visible: boolean): void {\n    this._layerManager?.setLayerVisibility(id, visible);\n  }\n\n  /**\n   * Zooms the map to a layer's extent.\n   *\n   * @param id - The layer id\n   */\n  zoomToLayer(id: string): void {\n    this._layerManager?.zoomToLayer(id);\n  }\n\n  /**\n   * Applies a style patch to a layer.\n   *\n   * @param id - The layer id\n   * @param style - Partial style update\n   */\n  setLayerStyle(id: string, style: Partial<VectorLayerStyle>): void {\n    this._layerManager?.setLayerStyle(id, style);\n  }\n\n  /**\n   * Sets a layer's master opacity, multiplied into every style opacity\n   * (fill, circle, and line layers alike).\n   *\n   * @param id - The layer id\n   * @param opacity - The new opacity (0-1)\n   */\n  setLayerOpacity(id: string, opacity: number): void {\n    this._layerManager?.setLayerOpacity(id, opacity);\n  }\n\n  /**\n   * Enables or disables the attribute popup for a layer.\n   *\n   * @param id - The layer id\n   * @param enabled - Whether clicking a feature opens a popup\n   */\n  setLayerPicker(id: string, enabled: boolean): void {\n    this._layerManager?.setLayerPicker(id, enabled);\n  }\n\n  /**\n   * Moves a layer's map layers before another map layer (or to the top\n   * when omitted).\n   *\n   * @param id - The layer id\n   * @param beforeId - Target map layer id, or undefined for the top\n   */\n  setLayerBeforeId(id: string, beforeId?: string): void {\n    this._layerManager?.setLayerBeforeId(id, beforeId);\n  }\n\n  /**\n   * Switches a layer between GeoJSON and dynamic tile rendering.\n   *\n   * @param id - The layer id\n   * @param mode - The requested render mode\n   */\n  async setRenderMode(id: string, mode: RenderMode): Promise<void> {\n    return this._manager().setRenderMode(id, mode);\n  }\n\n  /**\n   * Re-fetches a URL-backed layer's data and re-renders it in place,\n   * keeping the same layer id, source, style, render mode, and position.\n   * In-memory GeoJSON and File sources are static, so reloading them is a\n   * no-op that returns the current layer info.\n   *\n   * @param id - The layer id\n   * @returns The refreshed layer info, or undefined when no such layer exists\n   */\n  async reloadLayer(id: string): Promise<VectorLayerInfo | undefined> {\n    return this._layerManager?.reloadLayer(id);\n  }\n\n  // ---------------------------------------------------------------------\n  // State and events\n  // ---------------------------------------------------------------------\n\n  /**\n   * Gets the current state of the control.\n   *\n   * @returns The current control state\n   */\n  getState(): VectorState {\n    return {\n      ...this._state,\n      layers: this._layerManager?.getLayers() ?? this._state.layers,\n    };\n  }\n\n  /**\n   * Updates the control state.\n   *\n   * @param newState - Partial state to merge with current state\n   */\n  setState(newState: Partial<VectorState>): void {\n    this._state = { ...this._state, ...newState };\n    this._emit('statechange');\n  }\n\n  /**\n   * Toggles the collapsed state of the control panel.\n   */\n  toggle(): void {\n    this._state.collapsed = !this._state.collapsed;\n\n    if (this._panel) {\n      if (this._state.collapsed) {\n        this._panel.classList.remove('expanded');\n        this._emit('collapse');\n      } else {\n        this._panel.classList.add('expanded');\n        this._updatePanelPosition();\n        this._emit('expand');\n      }\n    }\n\n    this._emit('statechange');\n  }\n\n  /**\n   * Expands the control panel.\n   */\n  expand(): void {\n    if (this._state.collapsed) {\n      this.toggle();\n    }\n  }\n\n  /**\n   * Collapses the control panel.\n   */\n  collapse(): void {\n    if (!this._state.collapsed) {\n      this.toggle();\n    }\n  }\n\n  /**\n   * Registers an event handler.\n   *\n   * @param event - The event type to listen for\n   * @param handler - The callback function\n   */\n  on(event: VectorControlEvent, handler: VectorControlEventHandler): void {\n    if (!this._eventHandlers.has(event)) {\n      this._eventHandlers.set(event, new Set());\n    }\n    this._eventHandlers.get(event)!.add(handler);\n  }\n\n  /**\n   * Removes an event handler.\n   *\n   * @param event - The event type\n   * @param handler - The callback function to remove\n   */\n  off(event: VectorControlEvent, handler: VectorControlEventHandler): void {\n    this._eventHandlers.get(event)?.delete(handler);\n  }\n\n  /**\n   * Gets the map instance.\n   *\n   * @returns The MapLibre GL map instance or undefined if not added to a map\n   */\n  getMap(): MapLibreMap | undefined {\n    return this._map;\n  }\n\n  /**\n   * Gets the control container element.\n   *\n   * @returns The container element or undefined if not added to a map\n   */\n  getContainer(): HTMLElement | undefined {\n    return this._container;\n  }\n\n  /**\n   * Gets the panel content element that hosts the control UI.\n   *\n   * @returns The content element or undefined if not added to a map\n   */\n  getContentElement(): HTMLElement | undefined {\n    return this._content;\n  }\n\n  /**\n   * Returns the layer manager, throwing when the control has not been\n   * added to a map yet.\n   */\n  private _manager(): LayerManager {\n    if (!this._layerManager) {\n      throw new Error('VectorControl must be added to a map before loading data');\n    }\n    return this._layerManager;\n  }\n\n  /**\n   * Lazily creates the shared DuckDB engine on first use.\n   */\n  private _getEngine(): Promise<IEngine> {\n    if (!this._enginePromise) {\n      this._enginePromise = createEngine({\n        onProgress: (message) => this._emit('loading', { message }),\n        baseUrl: this._options.duckdbWasmBaseUrl,\n        sqlJsBaseUrl: this._options.sqlJsBaseUrl,\n        spatialExtensionPath: this._options.spatialExtensionPath,\n      });\n      // Allow a retry on the next request when engine creation fails\n      // (e.g. the CDN was unreachable).\n      this._enginePromise.catch(() => {\n        this._enginePromise = undefined;\n      });\n    }\n    return this._enginePromise;\n  }\n\n  /**\n   * Emits an event to all registered handlers.\n   *\n   * @param event - The event type to emit\n   * @param extra - Optional layer/error/message context\n   */\n  private _emit(\n    event: VectorControlEvent,\n    extra?: Pick<VectorEventPayload, 'layer' | 'error' | 'message'>,\n  ): void {\n    const handlers = this._eventHandlers.get(event);\n    if (handlers) {\n      const eventData: VectorEventPayload = { type: event, state: this.getState(), ...extra };\n      handlers.forEach((handler) => handler(eventData));\n    }\n    // Layer events also imply a state change for state subscribers.\n    if (event === 'layeradded' || event === 'layerremoved' || event === 'layerupdated') {\n      this._emit('statechange');\n    }\n  }\n\n  /**\n   * Creates the main container element for the control.\n   * Contains a toggle button (29x29) matching navigation control size.\n   *\n   * @returns The container element\n   */\n  private _createContainer(): HTMLElement {\n    const container = document.createElement('div');\n    container.className = `maplibregl-ctrl maplibregl-ctrl-group vector-control${\n      this._options.className ? ` ${this._options.className}` : ''\n    }`;\n\n    // Create toggle button (29x29 to match navigation control)\n    const toggleBtn = document.createElement('button');\n    toggleBtn.className = 'vector-control-toggle';\n    toggleBtn.type = 'button';\n    toggleBtn.setAttribute('aria-label', this._options.title);\n    // Vector geometry icon: a triangle of edges with vertex nodes\n    // (points, lines, and a polygon in one glyph)\n    toggleBtn.innerHTML = `\n      <span class=\"vector-control-icon\">\n        <svg viewBox=\"0 0 24 24\" width=\"22\" height=\"22\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n          <circle cx=\"5.5\" cy=\"5.5\" r=\"2.2\"/>\n          <circle cx=\"18.5\" cy=\"8.5\" r=\"2.2\"/>\n          <circle cx=\"11\" cy=\"19\" r=\"2.2\"/>\n          <path d=\"M7.7 6 16.3 8\"/>\n          <path d=\"M17.4 10.4 12 17.2\"/>\n          <path d=\"M10.3 16.9 6 7.6\"/>\n        </svg>\n      </span>\n    `;\n    toggleBtn.addEventListener('click', () => this.toggle());\n\n    container.appendChild(toggleBtn);\n\n    return container;\n  }\n\n  /**\n   * Creates the panel element with header and content areas.\n   * Panel is positioned as a dropdown below the toggle button.\n   *\n   * @returns The panel element\n   */\n  private _createPanel(): HTMLElement {\n    const panel = document.createElement('div');\n    panel.className = 'vector-control-panel';\n    panel.style.width = `${this._options.panelWidth}px`;\n\n    // Create header with title and close button\n    const header = document.createElement('div');\n    header.className = 'vector-control-header';\n\n    const title = document.createElement('span');\n    title.className = 'vector-control-title';\n    title.textContent = this._options.title;\n\n    const closeBtn = document.createElement('button');\n    closeBtn.className = 'vector-control-close';\n    closeBtn.type = 'button';\n    closeBtn.setAttribute('aria-label', 'Close panel');\n    closeBtn.innerHTML = '&times;';\n    closeBtn.addEventListener('click', () => this.collapse());\n\n    header.appendChild(title);\n    header.appendChild(closeBtn);\n\n    // Create content area (filled by the panel UI)\n    const content = document.createElement('div');\n    content.className = 'vector-control-content';\n    this._content = content;\n\n    panel.appendChild(header);\n    panel.appendChild(content);\n\n    if (this._options.resizable) {\n      this._addResizeHandles(panel);\n    }\n\n    return panel;\n  }\n\n  /**\n   * Adds drag handles in the panel's bottom-left and bottom-right\n   * corners. Pointer drags resize the panel and the chosen size is kept\n   * (in {@link _userWidth}/{@link _userHeight}) so repositioning does not\n   * reset it.\n   *\n   * @param panel - The panel element to attach handles to\n   */\n  private _addResizeHandles(panel: HTMLElement): void {\n    for (const side of ['left', 'right'] as const) {\n      const handle = document.createElement('div');\n      handle.className = `vector-control-resize-handle vector-control-resize-${side}`;\n      handle.setAttribute('aria-hidden', 'true');\n      handle.addEventListener('pointerdown', (event) =>\n        this._beginResize(event, side, panel, handle),\n      );\n      panel.appendChild(handle);\n    }\n  }\n\n  /**\n   * Starts a pointer-driven resize from one of the corner handles.\n   *\n   * The panel is first frozen to explicit left/top pixels (clearing any\n   * right/bottom anchor) so the opposite edge stays put no matter which\n   * corner the control sits in. The right handle then grows the panel\n   * rightward, the left handle leftward; both grow it downward. Sizes are\n   * clamped to a sensible minimum and to the map container.\n   *\n   * @param event - The pointerdown event\n   * @param side - Which corner handle started the drag\n   * @param panel - The panel element being resized\n   * @param handle - The handle element (for pointer capture)\n   */\n  private _beginResize(\n    event: PointerEvent,\n    side: 'left' | 'right',\n    panel: HTMLElement,\n    handle: HTMLElement,\n  ): void {\n    if (!this._mapContainer) return;\n    event.preventDefault();\n    // Keep the drag from bubbling to the document click-outside handler.\n    event.stopPropagation();\n\n    const mapRect = this._mapContainer.getBoundingClientRect();\n    const rect = panel.getBoundingClientRect();\n    const startX = event.clientX;\n    const startY = event.clientY;\n    const startWidth = rect.width;\n    const startHeight = rect.height;\n    const startLeft = rect.left - mapRect.left;\n    const startRight = rect.right;\n    const startTop = rect.top;\n\n    const EDGE_MARGIN = 10;\n    // Clamp the preferred minimums to what the map can actually hold, so a\n    // small map container never forces the panel past its edges.\n    const minWidth = Math.min(240, Math.max(120, mapRect.width - 2 * EDGE_MARGIN));\n    const minHeight = Math.min(160, Math.max(120, mapRect.height - 2 * EDGE_MARGIN));\n\n    // Pin the panel to its current rect so the size grows from the dragged\n    // corner regardless of the original anchor, and drop the CSS max-size\n    // caps for the duration of the drag.\n    panel.style.left = `${startLeft}px`;\n    panel.style.top = `${startTop - mapRect.top}px`;\n    panel.style.right = '';\n    panel.style.bottom = '';\n    panel.style.maxWidth = 'none';\n    panel.style.maxHeight = 'none';\n\n    const onMove = (moveEvent: PointerEvent) => {\n      const dx = moveEvent.clientX - startX;\n      const dy = moveEvent.clientY - startY;\n\n      const maxHeight = Math.max(minHeight, mapRect.bottom - startTop - EDGE_MARGIN);\n      const nextHeight = Math.max(minHeight, Math.min(startHeight + dy, maxHeight));\n\n      let nextWidth: number;\n      let nextLeft = startLeft;\n      if (side === 'right') {\n        const maxWidth = Math.max(minWidth, mapRect.right - rect.left - EDGE_MARGIN);\n        nextWidth = Math.max(minWidth, Math.min(startWidth + dx, maxWidth));\n      } else {\n        const maxWidth = Math.max(minWidth, startRight - mapRect.left - EDGE_MARGIN);\n        nextWidth = Math.max(minWidth, Math.min(startWidth - dx, maxWidth));\n        // Hold the right edge fixed while the left edge follows the drag.\n        nextLeft = startLeft + (startWidth - nextWidth);\n      }\n\n      panel.style.width = `${nextWidth}px`;\n      panel.style.height = `${nextHeight}px`;\n      panel.style.left = `${nextLeft}px`;\n      this._userWidth = nextWidth;\n      this._userHeight = nextHeight;\n    };\n\n    const cleanup = () => {\n      handle.releasePointerCapture?.(event.pointerId);\n      handle.removeEventListener('pointermove', onMove);\n      handle.removeEventListener('pointerup', cleanup);\n      handle.removeEventListener('pointercancel', cleanup);\n      this._resizeDragCleanup = null;\n    };\n\n    handle.setPointerCapture?.(event.pointerId);\n    handle.addEventListener('pointermove', onMove);\n    handle.addEventListener('pointerup', cleanup);\n    handle.addEventListener('pointercancel', cleanup);\n    this._resizeDragCleanup = cleanup;\n  }\n\n  /**\n   * Setup event listeners for panel positioning and click-outside behavior.\n   */\n  private _setupEventListeners(): void {\n    // Click outside to close (check both container and panel since they're\n    // now separate). Skipped when closeOnOutsideClick is false, so the\n    // panel stays open until the header close button is used.\n    if (this._options.closeOnOutsideClick !== false) {\n      this._clickOutsideHandler = (e: MouseEvent) => {\n        const target = e.target as Node;\n        // A click on panel UI can re-render the list before the event\n        // bubbles here, detaching its target; don't treat that as outside.\n        if (!target.isConnected) return;\n        if (\n          this._container &&\n          this._panel &&\n          !this._container.contains(target) &&\n          !this._panel.contains(target)\n        ) {\n          this.collapse();\n        }\n      };\n      document.addEventListener('click', this._clickOutsideHandler);\n    }\n\n    // Update panel position on window resize\n    this._resizeHandler = () => {\n      if (!this._state.collapsed) {\n        this._updatePanelPosition();\n      }\n    };\n    window.addEventListener('resize', this._resizeHandler);\n\n    // Update panel position on map resize (e.g., sidebar toggle)\n    this._mapResizeHandler = () => {\n      if (!this._state.collapsed) {\n        this._updatePanelPosition();\n      }\n    };\n    this._map?.on('resize', this._mapResizeHandler);\n  }\n\n  /**\n   * Detect which corner the control is positioned in.\n   *\n   * @returns The position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'\n   */\n  private _getControlPosition(): 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' {\n    const parent = this._container?.parentElement;\n    if (!parent) return 'top-right'; // Default\n\n    if (parent.classList.contains('maplibregl-ctrl-top-left')) return 'top-left';\n    if (parent.classList.contains('maplibregl-ctrl-top-right')) return 'top-right';\n    if (parent.classList.contains('maplibregl-ctrl-bottom-left')) return 'bottom-left';\n    if (parent.classList.contains('maplibregl-ctrl-bottom-right')) return 'bottom-right';\n\n    return 'top-right'; // Default\n  }\n\n  /**\n   * Update the panel position based on button location and control corner.\n   * Positions the panel next to the button, expanding in the appropriate direction.\n   */\n  private _updatePanelPosition(): void {\n    if (!this._container || !this._panel || !this._mapContainer) return;\n\n    // Get the toggle button (first child of container)\n    const button = this._container.querySelector('.vector-control-toggle');\n    if (!button) return;\n\n    const buttonRect = button.getBoundingClientRect();\n    const mapRect = this._mapContainer.getBoundingClientRect();\n    const position = this._getControlPosition();\n\n    // Calculate button position relative to map container\n    const buttonTop = buttonRect.top - mapRect.top;\n    const buttonBottom = mapRect.bottom - buttonRect.bottom;\n    const buttonLeft = buttonRect.left - mapRect.left;\n    const buttonRight = mapRect.right - buttonRect.right;\n\n    const panelGap = 5; // Gap between button and panel\n\n    // Reset all positioning\n    this._panel.style.top = '';\n    this._panel.style.bottom = '';\n    this._panel.style.left = '';\n    this._panel.style.right = '';\n\n    switch (position) {\n      case 'top-left':\n        // Panel expands down and to the right\n        this._panel.style.top = `${buttonTop + buttonRect.height + panelGap}px`;\n        this._panel.style.left = `${buttonLeft}px`;\n        break;\n\n      case 'top-right':\n        // Panel expands down and to the left\n        this._panel.style.top = `${buttonTop + buttonRect.height + panelGap}px`;\n        this._panel.style.right = `${buttonRight}px`;\n        break;\n\n      case 'bottom-left':\n        // Panel expands up and to the right\n        this._panel.style.bottom = `${buttonBottom + buttonRect.height + panelGap}px`;\n        this._panel.style.left = `${buttonLeft}px`;\n        break;\n\n      case 'bottom-right':\n        // Panel expands up and to the left\n        this._panel.style.bottom = `${buttonBottom + buttonRect.height + panelGap}px`;\n        this._panel.style.right = `${buttonRight}px`;\n        break;\n    }\n\n    // Constrain the panel to the map so it scrolls instead of\n    // overflowing on small screens.\n    const edgeMargin = 10;\n    const occupied =\n      (position.startsWith('top') ? buttonTop : buttonBottom) + buttonRect.height + panelGap;\n    const available = mapRect.height - occupied - edgeMargin;\n    this._panel.style.maxHeight = `${Math.max(120, available)}px`;\n    const availableWidth = Math.max(120, mapRect.width - 2 * edgeMargin);\n    this._panel.style.maxWidth = `${availableWidth}px`;\n    // Clamp the stylesheet's min-width too, or it overrides maxWidth\n    // on very narrow maps.\n    this._panel.style.minWidth = `${Math.min(240, availableWidth)}px`;\n\n    // Reapply a resize the user made, clamped to the current map size, so\n    // repositioning keeps their chosen dimensions instead of snapping back.\n    // The lower bound guards a tiny map where `available` can go negative.\n    if (this._userWidth !== null) {\n      this._panel.style.width = `${Math.max(120, Math.min(this._userWidth, availableWidth))}px`;\n    }\n    if (this._userHeight !== null) {\n      this._panel.style.height = `${Math.max(120, Math.min(this._userHeight, available))}px`;\n    }\n  }\n}\n"],"x_google_ignoreList":[5],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,GACd,KACA,WACA,OAC0B;CAC1B,MAAM,UAAU,SAAS,cAAc,GAAG;CAC1C,IAAI,WAAW,QAAQ,YAAY;CACnC,IAAI,OACF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,QAAQ,aAAa,KAAK,KAAK;CAGnC,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,QAAQ,OAAe,OAAO,IAAqB;CACjE,MAAM,OAAO,GAAG,QAAQ,yBAAyB;CACjD,KAAK,YAAY,mCAAmC,KAAK,YAAY,KAAK,sGAAsG,MAAM;CACtL,OAAO;AACT;;;;AAKA,IAAa,QAAQ;CACnB,KAAK;CACL,QACE;CACF,MAAM;CACN,OACE;CACF,SACE;CACF,QACE;CACF,aAAa;AACf;;;AC3BA,IAAM,+BAAe,IAAI,QAAuC;;;;;;;;;AAUhE,SAAgB,gBAAgB,SAAgD;CAG9E,IAAI,SAAS;CACb,IAAI,mBAAwC;CAE5C,MAAM,aACJ,SACI,QAAQ,QAAQ,CAAC,CAAC,IAClB,kBAAkB,UAAU,WAAW;EACrC,mBAAmB;CACrB,CAAC;CAIP,MAAM,aAFW,aAAa,IAAI,QAAQ,SAAS,KAAK,QAAQ,QAAQ,GAE7C,KAAK,MAAM,IAAI;CAC1C,aAAa,IAAI,QAAQ,WAAW,SAAS;CAE7C,OAAO;EACL;EACA,aAAa;GACX,SAAS;GACT,mBAAmB;EACrB;CACF;AACF;;;;;;AAOA,SAAS,kBACP,SACA,gBACmB;CACnB,MAAM,EAAE,WAAW,QAAQ,eAAe;CAE1C,OAAO,IAAI,SAAmB,YAAY;EACxC,MAAM,UAAU,6BAA6B,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;EAEnF,MAAM,UAAU,GAAG,OAAO,6BAA6B;EACvD,MAAM,SAAS,GAAG,OAAO,sCAAsC;GAC7D,MAAM;GACN,cAAc;GACd,mBAAmB;EACrB,CAAC;EAED,MAAM,QAAQ,GAAG,OAAO,qCAAqC,EAAE,IAAI,QAAQ,CAAC;EAC5E,MAAM,cAAc;EACpB,MAAM,WAAW,GAAG,OAAO,sCAAsC;EACjE,SAAS,cAAc,GAAG,WAAW,YAAY,OAAO,OAAO;EAI/D,MAAM,eAAe,GAAG,SAAS,iCAAiC;EAClE,MAAM,YAAY,GAAG,SAAS,yBAAyB;EACvD,UAAU,OAAO;EACjB,UAAU,UAAU;EACpB,MAAM,gBAAgB,GAAG,MAAM;EAC/B,cAAc,cAAc;EAC5B,aAAa,YAAY,SAAS;EAClC,aAAa,YAAY,aAAa;EAEtC,MAAM,OAAO,GAAG,OAAO,kCAAkC;EACzD,MAAM,QAA4B,CAAC;EACnC,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,MAAM,GAAG,SAAS,kCAAkC;GAC1D,MAAM,MAAM,GAAG,SAAS,yBAAyB;GACjD,IAAI,OAAO;GACX,IAAI,UAAU;GACd,IAAI,QAAQ;GACZ,MAAM,OAAO,GAAG,QAAQ,kCAAkC;GAE1D,KAAK,cAAc;GACnB,KAAK,QAAQ;GACb,IAAI,YAAY,GAAG;GACnB,IAAI,YAAY,IAAI;GACpB,KAAK,YAAY,GAAG;GACpB,MAAM,KAAK,GAAG;EAChB;EAEA,MAAM,SAAS,GAAG,OAAO,oCAAoC;EAC7D,MAAM,eAAe,GAAG,UAAU,yDAAyD,EACzF,MAAM,SACR,CAAC;EACD,aAAa,cAAc;EAC3B,MAAM,aAAa,GAAG,UAAU,yBAAyB,EAAE,MAAM,SAAS,CAAC;EAC3E,OAAO,YAAY,YAAY;EAC/B,OAAO,YAAY,UAAU;EAE7B,MAAM,eAAyB,MAAM,QAAQ,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,KAAK;EAExF,MAAM,kBAAwB;GAC5B,MAAM,QAAQ,OAAO,EAAE;GACvB,UAAU,UAAU,UAAU,OAAO;GACrC,UAAU,gBAAgB,QAAQ,KAAK,QAAQ,OAAO;GACtD,WAAW,WAAW,UAAU;GAChC,WAAW,cAAc,UAAU,IAAI,iBAAiB,QAAQ,MAAM;EACxE;EAEA,KAAK,MAAM,OAAO,OAAO,IAAI,iBAAiB,UAAU,SAAS;EACjE,UAAU,iBAAiB,gBAAgB;GACzC,KAAK,MAAM,OAAO,OAAO,IAAI,UAAU,UAAU;GACjD,UAAU;EACZ,CAAC;EACD,UAAU;EAEV,IAAI,UAAU;EACd,MAAM,UAAU,WAA2B;GACzC,IAAI,SAAS;GACb,UAAU;GACV,QAAQ,OAAO;GACf,QAAQ,MAAM;EAChB;EAEA,aAAa,iBAAiB,eAAe,OAAO,CAAC,CAAC,CAAC;EACvD,WAAW,iBAAiB,eAAe,OAAO,OAAO,CAAC,CAAC;EAE3D,QAAQ,iBAAiB,cAAc,UAAU;GAC/C,IAAI,MAAM,WAAW,SAAS,OAAO,CAAC,CAAC;EACzC,CAAC;EAGD,KAAK,MAAM,QAAQ;GAAC;GAAa;GAAS;GAAY;EAAO,GAC3D,QAAQ,iBAAiB,OAAO,UAAU,MAAM,gBAAgB,CAAC;EAEnE,QAAQ,iBAAiB,YAAY,UAAU;GAC7C,IAAI,MAAM,QAAQ,UAAU;IAC1B,MAAM,gBAAgB;IACtB,OAAO,CAAC,CAAC;GACX;EACF,CAAC;EAED,OAAO,YAAY,KAAK;EACxB,OAAO,YAAY,QAAQ;EAC3B,OAAO,YAAY,YAAY;EAC/B,OAAO,YAAY,IAAI;EACvB,OAAO,YAAY,MAAM;EACzB,QAAQ,YAAY,MAAM;EAC1B,UAAU,YAAY,OAAO;EAI7B,UAAU,MAAM;EAEhB,qBAAqB,OAAO,CAAC,CAAC,CAAC;CACjC,CAAC;AACH;;;;;;AC/KA,IAAM,oBAAkD;CACtD,SAAS;CACT,MAAM;CACN,MAAM;CACN,KAAK;CACL,KAAK;CACL,SAAS;CACT,YAAY;CACZ,IAAI;CACJ,KAAK;CACL,KAAK;CACL,KAAK;CAGL,KAAK;AACP;;;;;;;AAQA,SAAgB,gBAAgB,KAAqB;CACnD,MAAM,eAAe,IAAI,MAAM,MAAM,EAAE;CACvC,MAAM,WAAW,aAAa,MAAM,GAAG;CACvC,OAAO,SAAS,SAAS,SAAS,MAAM;AAC1C;;;;;;;;;;;AAYA,SAAgB,mBAAmB,UAAgC;CACjE,MAAM,QAAQ,kBAAkB,KAAK,SAAS,KAAK,CAAC;CACpD,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,YAAY,MAAM,GAAG,YAAY;CACvC,OAAO,kBAAkB,cAAc;AACzC;;;;;;;AAQA,SAAgB,SAAS,UAA0B;CACjD,OAAO,SAAS,QAAQ,iBAAiB,EAAE,KAAK;AAClD;;;;AAKA,IAAM,eAA8C;CAClD,CAAC,QAAQ,SAAS;CAClB,CAAC,qBAAqB,KAAK;CAC3B,CAAC,WAAW,YAAY;AAC1B;;;;;;;;;;AAWA,SAAgB,kBAAkB,KAA2B;CAC3D,MAAM,OAAO,IAAI,MAAM,CAAc,EAAE,MAAM,MAAM,EAAE,GAAG,YAAY;CACpE,KAAK,MAAM,CAAC,SAAS,WAAW,cAC9B,IAAI,QAAQ,KAAK,IAAI,GAAG,OAAO;CAEjC,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,aACd,QACA,gBACgB;CAChB,IAAI,OAAO,WAAW,UAAU;EAC9B,IAAI,OAAO,WAAW,OAAO,GAC3B,OAAO;GAAE,QAAQ,kBAAkB,kBAAkB,MAAM;GAAG,MAAM;EAAW;EAEjF,MAAM,OAAO,gBAAgB,MAAM;EACnC,OAAO;GACL,QAAQ,kBAAkB,mBAAmB,IAAI;GACjD,MAAM,SAAS,IAAI;EACrB;CACF;CAEA,IAAI,OAAO,SAAS,eAAe,kBAAkB,MACnD,OAAO;EACL,QAAQ,kBAAkB,mBAAmB,OAAO,IAAI;EACxD,MAAM,SAAS,OAAO,IAAI;CAC5B;CAGF,IAAI,OAAO,SAAS,eAAe,kBAAkB,MACnD,OAAO;EAAE,QAAQ,kBAAkB;EAAW,MAAM;CAAW;CAIjE,OAAO;EAAE,QAAQ,kBAAkB;EAAW,MAAM;CAAU;AAChE;;;;;;;;;AC1HA,SAAgB,qBAAqB,MAAgC;CACnE,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,cACH,OAAO;EACT,KAAK;EACL,KAAK,mBACH,OAAO;EACT,KAAK;EACL,KAAK,gBACH,OAAO;EACT,KAAK,sBACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;;;;AASA,SAAgB,sBACd,SACA,MACkB;CAClB,IAAI,CAAC,WAAW,YAAY,WAAW,OAAO;CAC9C,IAAI,SAAS,WAAW,OAAO;CAC/B,OAAO,YAAY,OAAO,UAAU;AACtC;;;;;;;AAQA,SAAgB,oBAAoB,MAAkC;CACpE,IAAI,KAAK,SAAS,qBAAqB,OAAO;CAC9C,IAAI,KAAK,SAAS,WAAW,OAAO;EAAE,MAAM;EAAqB,UAAU,CAAC,IAAI;CAAE;CAClF,OAAO;EACL,MAAM;EACN,UAAU,CAAC;GAAE,MAAM;GAAW,UAAU;GAAkB,YAAY,CAAC;EAAE,CAAC;CAC5E;AACF;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,eAAe,YAA8C;CAC3E,MAAM,OAAQ,WAA6D,KAAK,YAAY;CAC5F,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,MAAM,QAAQ,KAAK,YAAY;CAG/B,IAAI,MAAM,SAAS,OAAO,KAAK,sBAAsB,KAAK,KAAK,GAAG,OAAO;CAGzE,MAAM,QAAQ,MAAM,MAAM,aAAa;CACvC,OAAO,QAAQ,QAAQ,MAAM,OAAO;AACtC;AAEA,SAAS,wBAAwB,MAAY,QAAuB;CAClE,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;CAC5B,IAAI,OAAO,OAAO,OAAO,UAAU;EACjC,MAAM,CAAC,GAAG,KAAK;EACf,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK;EAC3B,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK;EAC3B,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK;EAC3B,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK;EAC3B;CACF;CACA,KAAK,MAAM,SAAS,QAClB,wBAAwB,MAAM,KAAK;AAEvC;AAEA,SAAS,uBAAuB,MAAY,UAAiC;CAC3E,IAAI,CAAC,UAAU;CACf,IAAI,SAAS,SAAS,sBAAsB;EAC1C,KAAK,MAAM,SAAS,SAAS,YAC3B,uBAAuB,MAAM,KAAK;EAEpC;CACF;CACA,wBAAwB,MAAM,SAAS,WAAW;AACpD;;;;;;;;AAkBA,SAAgB,2BAA2B,YAA+C;CACxF,MAAM,OAAa;EAAC;EAAU;EAAU;EAAW;CAAS;CAC5D,IAAI;CAEJ,KAAK,MAAM,WAAW,WAAW,UAC/B,IAAI,QAAQ,UAAU;EACpB,WAAW,sBAAsB,UAAU,qBAAqB,QAAQ,SAAS,IAAI,CAAC;EACtF,uBAAuB,MAAM,QAAQ,QAAQ;CAC/C;CAGF,OAAO;EACL,cAAc,WAAW,SAAS;EAClC,cAAc,YAAY;EAC1B,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,KAAK,OAAO,KAAA;CAC1D;AACF;;;;;;;;;AAUA,SAAgB,kBAAkB,YAAyC;CACzE,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,WAAW,WAAW,UAAuB;EACtD,IAAI,CAAC,QAAQ,YAAY;EACzB,KAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,UAAU,GAAG,MAAM,IAAI,GAAG;CAClE;CACA,OAAO,MAAM,KAAK,KAAK;AACzB;;;;;;ACnKA,IAAM,gBAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;;;;AASD,SAAgB,iBAAiB,OAAkC;CACjE,OACE,OAAO,UAAU,YACjB,UAAU,QACV,cAAc,IAAK,MAA6B,IAAc;AAElE;;;;;;;;;;;;;;;;;;;;;;;AAwBA,eAAsB,mBACpB,KACqE;CACrE,IAAI,CAAC,gBAAgB,KAAK,GAAG,GAAG,OAAO;CAEvC,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,MAAM,GAAG;CAC5B,QAAQ;EAGN,OAAO;CACT;CACA,IAAI,CAAC,SAAS,IAAI,OAAO;CAEzB,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;CAC5D,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;EAG9B,MAAM,SAAS,MAAM,OAAO,EAAE,YAAY,KAAA,CAAS;EACnD,OAAO;CACT;CAEA,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,SAAS,KAAK;CAC7B,QAAQ;EACN,OAAO;CACT;CAEA,IAAI;CACJ,IAAI;EACF,SAAS,KAAK,MAAM,IAAI;CAC1B,QAAQ;EAEN,OAAO;CACT;CAEA,IAAI,CAAC,iBAAiB,MAAM,GAAG,OAAO;CACtC,OAAO;EAAE,YAAY,oBAAoB,MAAM;EAAG,UAAU,KAAK;CAAO;AAC1E;;;ACjEA,IAAI,KAAK,YAAY,MAAM,aAAa,MAAM;AAE9C,IAAI,OAAO,IAAI,GAAG;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAgB;CAAG;CAAoB;AAAC,CAAC;AAEhJ,IAAI,OAAO,IAAI,GAAG;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAiB;CAAG;AAAC,CAAC;AAEvI,IAAI,OAAO,IAAI,GAAG;CAAC;CAAI;CAAI;CAAI;CAAG;CAAG;CAAG;CAAG;CAAG;CAAI;CAAG;CAAI;CAAG;CAAI;CAAG;CAAI;CAAG;CAAI;CAAG;AAAE,CAAC;AAEpF,IAAI,OAAO,SAAU,IAAI,OAAO;CAC5B,IAAI,IAAI,IAAI,IAAI,EAAE;CAClB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,EAAE,GACtB,EAAE,KAAK,SAAS,KAAK,GAAG,IAAI;CAGhC,IAAI,IAAI,IAAI,IAAI,EAAE,GAAG;CACrB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,EAAE,GACtB,KAAK,IAAI,IAAI,EAAE,IAAI,IAAI,EAAE,IAAI,IAAI,EAAE,GAC/B,EAAE,KAAO,IAAI,EAAE,MAAO,IAAK;CAGnC,OAAO;EAAK;EAAM;CAAE;AACxB;AACA,IAAI,KAAK,KAAK,MAAM,CAAC,GAAG,KAAK,GAAG,GAAG,QAAQ,GAAG;AAE9C,GAAG,MAAM,KAAK,MAAM,OAAO;AAC3B,IAAI,KAAK,KAAK,MAAM,CAAC,GAAG,KAAK,GAAG;AAAW,GAAG;AAE9C,IAAI,MAAM,IAAI,IAAI,KAAK;AACvB,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,EAAE,GAAG;CAE5B,IAAI,KAAM,IAAI,UAAW,KAAO,IAAI,UAAW;CAC/C,KAAM,IAAI,UAAW,KAAO,IAAI,UAAW;CAC3C,KAAM,IAAI,UAAW,KAAO,IAAI,SAAW;CAC3C,IAAI,OAAQ,IAAI,UAAW,KAAO,IAAI,QAAW,MAAO;AAC5D;AAIA,IAAI,QAAQ,SAAU,IAAI,IAAI,GAAG;CAC7B,IAAI,IAAI,GAAG;CAEX,IAAI,IAAI;CAER,IAAI,IAAI,IAAI,IAAI,EAAE;CAElB,OAAO,IAAI,GAAG,EAAE,GACZ,IAAI,GAAG,IACH,EAAE,EAAE,GAAG,KAAK;CAGpB,IAAI,KAAK,IAAI,IAAI,EAAE;CACnB,KAAK,IAAI,GAAG,IAAI,IAAI,EAAE,GAClB,GAAG,KAAM,GAAG,IAAI,KAAK,EAAE,IAAI,MAAO;CAEtC,IAAI;CACJ,IAAI,GAAG;EAEH,KAAK,IAAI,IAAI,KAAK,EAAE;EAEpB,IAAI,MAAM,KAAK;EACf,KAAK,IAAI,GAAG,IAAI,GAAG,EAAE,GAEjB,IAAI,GAAG,IAAI;GAEP,IAAI,KAAM,KAAK,IAAK,GAAG;GAEvB,IAAI,MAAM,KAAK,GAAG;GAElB,IAAI,IAAI,GAAG,GAAG,KAAK,QAAQ;GAE3B,KAAK,IAAI,IAAI,KAAM,KAAK,OAAO,GAAI,KAAK,GAAG,EAAE,GAEzC,GAAG,IAAI,MAAM,OAAO;EAE5B;CAER,OACK;EACD,KAAK,IAAI,IAAI,CAAC;EACd,KAAK,IAAI,GAAG,IAAI,GAAG,EAAE,GACjB,IAAI,GAAG,IACH,GAAG,KAAK,IAAI,GAAG,GAAG,KAAK,SAAU,KAAK,GAAG;CAGrD;CACA,OAAO;AACX;AAEA,IAAI,MAAM,IAAI,GAAG,GAAG;AACpB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,EAAE,GACvB,IAAI,KAAK;AACb,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE,GACzB,IAAI,KAAK;AACb,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE,GACzB,IAAI,KAAK;AACb,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,EAAE,GACzB,IAAI,KAAK;AAEb,IAAI,MAAM,IAAI,GAAG,EAAE;AACnB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,EAAE,GACtB,IAAI,KAAK;AAEb,IAAyC,OAAqB,mBAAK,KAAK,GAAG,CAAC,GAEnC,OAAqB,mBAAK,KAAK,GAAG,CAAC;AAE5E,IAAI,MAAM,SAAU,GAAG;CACnB,IAAI,IAAI,EAAE;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,EAAE,GAC5B,IAAI,EAAE,KAAK,GACP,IAAI,EAAE;CAEd,OAAO;AACX;AAEA,IAAI,OAAO,SAAU,GAAG,GAAG,GAAG;CAC1B,IAAI,IAAK,IAAI,IAAK;CAClB,QAAS,EAAE,KAAM,EAAE,IAAI,MAAM,OAAQ,IAAI,KAAM;AACnD;AAEA,IAAI,SAAS,SAAU,GAAG,GAAG;CACzB,IAAI,IAAK,IAAI,IAAK;CAClB,QAAS,EAAE,KAAM,EAAE,IAAI,MAAM,IAAM,EAAE,IAAI,MAAM,QAAS,IAAI;AAChE;AAEA,IAAI,OAAO,SAAU,GAAG;CAAE,QAAS,IAAI,KAAK,IAAK;AAAG;AAGpD,IAAI,MAAM,SAAU,GAAG,GAAG,GAAG;CACzB,IAAI,KAAK,QAAQ,IAAI,GACjB,IAAI;CACR,IAAI,KAAK,QAAQ,IAAI,EAAE,QACnB,IAAI,EAAE;CAEV,OAAO,IAAI,GAAG,EAAE,SAAS,GAAG,CAAC,CAAC;AAClC;AAsBA,IAAI,KAAK;CACL;CACA;CACA;CACA;CACA;CACA;;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;AAEJ;AAEA,IAAI,MAAM,SAAU,KAAK,KAAK,IAAI;CAC9B,IAAI,IAAI,IAAI,MAAM,OAAO,GAAG,IAAI;CAChC,EAAE,OAAO;CACT,IAAI,MAAM,mBACN,MAAM,kBAAkB,GAAG,GAAG;CAClC,IAAI,CAAC,IACD,MAAM;CACV,OAAO;AACX;AAEA,IAAI,QAAQ,SAAU,KAAK,IAAI,KAAK,MAAM;CAEtC,IAAI,KAAK,IAAI,QAAQ,KAAK,OAAO,KAAK,SAAS;CAC/C,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,GACnB,OAAO,OAAO,IAAI,GAAG,CAAC;CAC1B,IAAI,QAAQ,CAAC;CAEb,IAAI,SAAS,SAAS,GAAG,KAAK;CAE9B,IAAI,OAAO,GAAG;CAEd,IAAI,OACA,MAAM,IAAI,GAAG,KAAK,CAAC;CAEvB,IAAI,OAAO,SAAU,GAAG;EACpB,IAAI,KAAK,IAAI;EAEb,IAAI,IAAI,IAAI;GAER,IAAI,OAAO,IAAI,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC;GACrC,KAAK,IAAI,GAAG;GACZ,MAAM;EACV;CACJ;CAEA,IAAI,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,GAAG,KAAK,GAAG,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG;CAEnG,IAAI,OAAO,KAAK;CAChB,GAAG;EACC,IAAI,CAAC,IAAI;GAEL,QAAQ,KAAK,KAAK,KAAK,CAAC;GAExB,IAAI,OAAO,KAAK,KAAK,MAAM,GAAG,CAAC;GAC/B,OAAO;GACP,IAAI,CAAC,MAAM;IAEP,IAAI,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI,IAAI,IAAI,KAAM,IAAI,IAAI,MAAM,GAAI,IAAI,IAAI;IACnE,IAAI,IAAI,IAAI;KACR,IAAI,MACA,IAAI,CAAC;KACT;IACJ;IAEA,IAAI,QACA,KAAK,KAAK,CAAC;IAEf,IAAI,IAAI,IAAI,SAAS,GAAG,CAAC,GAAG,EAAE;IAE9B,GAAG,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,IAAI,GAAG,GAAG,IAAI;IAC3C;GACJ,OACK,IAAI,QAAQ,GACb,KAAK,MAAM,KAAK,MAAM,MAAM,GAAG,MAAM;QACpC,IAAI,QAAQ,GAAG;IAEhB,IAAI,OAAO,KAAK,KAAK,KAAK,EAAE,IAAI,KAAK,QAAQ,KAAK,KAAK,MAAM,IAAI,EAAE,IAAI;IACvE,IAAI,KAAK,OAAO,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI;IACzC,OAAO;IAEP,IAAI,MAAM,IAAI,GAAG,EAAE;IAEnB,IAAI,MAAM,IAAI,GAAG,EAAE;IACnB,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,EAAE,GAEzB,IAAI,KAAK,MAAM,KAAK,KAAK,MAAM,IAAI,GAAG,CAAC;IAE3C,OAAO,QAAQ;IAEf,IAAI,MAAM,IAAI,GAAG,GAAG,UAAU,KAAK,OAAO;IAE1C,IAAI,MAAM,KAAK,KAAK,KAAK,CAAC;IAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK;KACrB,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,MAAM;KAEjC,OAAO,IAAI;KAEX,IAAI,IAAI,KAAK;KAEb,IAAI,IAAI,IACJ,IAAI,OAAO;UAEV;MAED,IAAI,IAAI,GAAG,IAAI;MACf,IAAI,KAAK,IACL,IAAI,IAAI,KAAK,KAAK,KAAK,CAAC,GAAG,OAAO,GAAG,IAAI,IAAI,IAAI;WAChD,IAAI,KAAK,IACV,IAAI,IAAI,KAAK,KAAK,KAAK,CAAC,GAAG,OAAO;WACjC,IAAI,KAAK,IACV,IAAI,KAAK,KAAK,KAAK,KAAK,GAAG,GAAG,OAAO;MACzC,OAAO,KACH,IAAI,OAAO;KACnB;IACJ;IAEA,IAAI,KAAK,IAAI,SAAS,GAAG,IAAI,GAAG,KAAK,IAAI,SAAS,IAAI;IAEtD,MAAM,IAAI,EAAE;IAEZ,MAAM,IAAI,EAAE;IACZ,KAAK,KAAK,IAAI,KAAK,CAAC;IACpB,KAAK,KAAK,IAAI,KAAK,CAAC;GACxB,OAEI,IAAI,CAAC;GACT,IAAI,MAAM,MAAM;IACZ,IAAI,MACA,IAAI,CAAC;IACT;GACJ;EACJ;EAGA,IAAI,QACA,KAAK,KAAK,MAAM;EACpB,IAAI,OAAO,KAAK,OAAO,GAAG,OAAO,KAAK,OAAO;EAC7C,IAAI,OAAO;EACX,QAAQ,OAAO,KAAK;GAEhB,IAAI,IAAI,GAAG,OAAO,KAAK,GAAG,IAAI,MAAM,MAAM,KAAK;GAC/C,OAAO,IAAI;GACX,IAAI,MAAM,MAAM;IACZ,IAAI,MACA,IAAI,CAAC;IACT;GACJ;GACA,IAAI,CAAC,GACD,IAAI,CAAC;GACT,IAAI,MAAM,KACN,IAAI,QAAQ;QACX,IAAI,OAAO,KAAK;IACjB,OAAO,KAAK,KAAK;IACjB;GACJ,OACK;IACD,IAAI,MAAM,MAAM;IAEhB,IAAI,MAAM,KAAK;KAEX,IAAI,IAAI,MAAM,KAAK,IAAI,KAAK;KAC5B,MAAM,KAAK,KAAK,MAAM,KAAK,KAAK,CAAC,IAAI,GAAG;KACxC,OAAO;IACX;IAEA,IAAI,IAAI,GAAG,OAAO,KAAK,GAAG,IAAI,MAAM,OAAO,KAAK;IAChD,IAAI,CAAC,GACD,IAAI,CAAC;IACT,OAAO,IAAI;IACX,IAAI,KAAK,GAAG;IACZ,IAAI,OAAO,GAAG;KACV,IAAI,IAAI,KAAK;KACb,MAAM,OAAO,KAAK,GAAG,KAAK,KAAK,KAAK,GAAG,OAAO;IAClD;IACA,IAAI,MAAM,MAAM;KACZ,IAAI,MACA,IAAI,CAAC;KACT;IACJ;IACA,IAAI,QACA,KAAK,KAAK,MAAM;IACpB,IAAI,MAAM,KAAK;IACf,IAAI,KAAK,IAAI;KACT,IAAI,QAAQ,KAAK,IAAI,OAAO,KAAK,IAAI,IAAI,GAAG;KAC5C,IAAI,QAAQ,KAAK,GACb,IAAI,CAAC;KACT,OAAO,KAAK,MAAM,EAAE,IAChB,IAAI,MAAM,KAAK,QAAQ;IAC/B;IACA,OAAO,KAAK,KAAK,EAAE,IACf,IAAI,MAAM,IAAI,KAAK;GAC3B;EACJ;EACA,GAAG,IAAI,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,IAAI,GAAG,IAAI;EAC1C,IAAI,IACA,QAAQ,GAAG,GAAG,IAAI,KAAK,GAAG,IAAI,IAAI,GAAG,IAAI;CACjD,SAAS,CAAC;CAEV,OAAO,MAAM,IAAI,UAAU,QAAQ,IAAI,KAAK,GAAG,EAAE,IAAI,IAAI,SAAS,GAAG,EAAE;AAC3E;AAoOA,IAAI,mBAAmB,IAAI,GAAG,CAAC;AA4U/B,IAAI,KAAK,SAAU,GAAG,GAAG;CAAE,OAAO,EAAE,KAAM,EAAE,IAAI,MAAM;AAAI;AAE1D,IAAI,KAAK,SAAU,GAAG,GAAG;CAAE,QAAQ,EAAE,KAAM,EAAE,IAAI,MAAM,IAAM,EAAE,IAAI,MAAM,KAAO,EAAE,IAAI,MAAM,QAAS;AAAG;AACxG,IAAI,KAAK,SAAU,GAAG,GAAG;CAAE,OAAO,GAAG,GAAG,CAAC,IAAK,GAAG,GAAG,IAAI,CAAC,IAAI;AAAa;;;;;;;AAwP1E,SAAgB,YAAY,MAAM,MAAM;CACpC,OAAO,MAAM,MAAM,EAAE,GAAG,EAAE,GAAG,QAAQ,KAAK,KAAK,QAAQ,KAAK,UAAU;AAC1E;AA0bA,IAAI,KAAK,OAAO,eAAe,6BAA6B,IAAI,YAAY;AAG5E,IAAI;CACA,GAAG,OAAO,IAAI,EAAE,QAAQ,KAAK,CAAC;AAElC,SACO,GAAG,CAAE;AAEZ,IAAI,QAAQ,SAAU,GAAG;CACrB,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK;EACtB,IAAI,IAAI,EAAE;EACV,IAAI,MAAM,IAAI,QAAQ,IAAI,QAAQ,IAAI;EACtC,IAAI,IAAI,KAAK,EAAE,QACX,OAAO;GAAE,GAAG;GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;EAAE;EACpC,IAAI,CAAC,IACD,KAAK,OAAO,aAAa,CAAC;OACzB,IAAI,MAAM,GACX,MAAM,IAAI,OAAO,MAAM,EAAE,OAAO,OAAO,MAAM,EAAE,OAAO,OAAO,IAAK,EAAE,OAAO,MAAO,OAC9E,KAAK,OAAO,aAAa,QAAS,KAAK,IAAK,QAAS,IAAI,IAAK;OAEjE,IAAI,KAAK,GACV,KAAK,OAAO,cAAc,IAAI,OAAO,IAAK,EAAE,OAAO,EAAG;OAEtD,KAAK,OAAO,cAAc,IAAI,OAAO,MAAM,EAAE,OAAO,OAAO,IAAK,EAAE,OAAO,EAAG;CACpF;AACJ;;;;;;;;AA4HA,SAAgB,UAAU,KAAK,QAAQ;CACnC,IAAI,QAAQ;EACR,IAAI,IAAI;EACR,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,OACjC,KAAK,OAAO,aAAa,MAAM,MAAM,IAAI,SAAS,GAAG,IAAI,KAAK,CAAC;EACnE,OAAO;CACX,OACK,IAAI,IACL,OAAO,GAAG,OAAO,GAAG;MAEnB;EACD,IAAI,KAAK,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG;EACtC,IAAI,EAAE,QACF,IAAI,CAAC;EACT,OAAO;CACX;AACJ;AAKA,IAAI,OAAO,SAAU,GAAG,GAAG;CAAE,OAAO,IAAI,KAAK,GAAG,GAAG,IAAI,EAAE,IAAI,GAAG,GAAG,IAAI,EAAE;AAAG;AAE5E,IAAI,KAAK,SAAU,GAAG,GAAG,GAAG;CACxB,IAAI,MAAM,GAAG,GAAG,IAAI,EAAE,GAAG,KAAK,UAAU,EAAE,SAAS,IAAI,IAAI,IAAI,KAAK,GAAG,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC,IAAI,KAAK,GAAG,KAAK,IAAI,KAAK,KAAK,KAAK,GAAG,GAAG,IAAI,EAAE;CACvI,IAAI,KAAK,KAAK,MAAM,aAAa,KAAK,GAAG,EAAE,IAAI;EAAC;EAAI,GAAG,GAAG,IAAI,EAAE;EAAG,GAAG,GAAG,IAAI,EAAE;CAAC,GAAG,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,MAAM,GAAG;CACpH,OAAO;EAAC,GAAG,GAAG,IAAI,EAAE;EAAG;EAAI;EAAI;EAAI,KAAK,GAAG,GAAG,IAAI,EAAE,IAAI,GAAG,GAAG,IAAI,EAAE;EAAG;CAAG;AAC9E;AAEA,IAAI,OAAO,SAAU,GAAG,GAAG;CACvB,OAAO,GAAG,GAAG,CAAC,KAAK,GAAG,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC;CAE1C,OAAO;EAAC,GAAG,GAAG,IAAI,EAAE;EAAG,GAAG,GAAG,IAAI,CAAC;EAAG,GAAG,GAAG,IAAI,EAAE;CAAC;AACtD;;;;;;;;AAwxBA,SAAgB,UAAU,MAAM,MAAM;CAClC,IAAI,QAAQ,CAAC;CACb,IAAI,IAAI,KAAK,SAAS;CACtB,OAAO,GAAG,MAAM,CAAC,KAAK,WAAW,EAAE,GAC/B,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,OACxB,IAAI,EAAE;CAGd,IAAI,IAAI,GAAG,MAAM,IAAI,CAAC;CACtB,IAAI,CAAC,GACD,OAAO,CAAC;CACZ,IAAI,IAAI,GAAG,MAAM,IAAI,EAAE;CACvB,IAAI,IAAI,KAAK,cAAc,KAAK;CAChC,IAAI,GAAG;EACH,IAAI,KAAK,GAAG,MAAM,IAAI,EAAE;EACxB,IAAI,GAAG,MAAM,EAAE,KAAK;EACpB,IAAI,GAAG;GACH,IAAI,GAAG,MAAM,KAAK,EAAE;GACpB,IAAI,GAAG,MAAM,KAAK,EAAE;EACxB;CACJ;CACA,IAAI,OAAO,QAAQ,KAAK;CACxB,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,EAAE,GAAG;EACxB,IAAI,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,MAAM,GAAG,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,MAAM,GAAG,IAAI,IAAI,KAAK,MAAM,GAAG;EACrH,IAAI;EACJ,IAAI,CAAC,QAAQ,KAAK;GACd,MAAM;GACN,MAAM;GACN,cAAc;GACd,aAAa;EACjB,CAAC,GACG,IAAI,CAAC,KACD,MAAM,MAAM,IAAI,MAAM,GAAG,IAAI,EAAE;OAC9B,IAAI,OAAO,GACZ,MAAM,MAAM,YAAY,KAAK,SAAS,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC;OAErE,IAAI,IAAI,8BAA8B,GAAG;CAErD;CACA,OAAO;AACX;;;ACrmFA,IAAM,WAAW;AACjB,IAAM,aAAa;AASnB,SAAS,SAAS,SAAkB,MAAyB;CAC3D,OAAO,MAAM,KAAK,QAAQ,QAAQ,EAAE,QACjC,UAAU,MAAM,UAAU,YAAY,MAAM,KAAK,YAAY,CAChE;AACF;AAEA,SAAS,MAAM,SAAkB,MAAmC;CAClE,OAAO,SAAS,SAAS,IAAI,EAAE;AACjC;AAEA,SAAS,UAAU,SAAkB,MAAkC;CAErE,OADc,MAAM,SAAS,IAAI,GAAG,aAAa,KAAK,KACtC,KAAA;AAClB;AAEA,SAAS,aACP,SACA,MACkC;CAClC,MAAM,aAAa,UACjB,MACG,MAAM,MAAM,EAAE,GACd,QAAQ,OAAO,GAAG,EAClB,QAAQ,UAAU,EAAE,EACpB,YAAY;CACjB,MAAM,SAAS,UAAU,IAAI;CAC7B,MAAM,QAAQ,OAAO,QAAQ,OAAO,EAAE,MAAM,CAAC,UAAU,UAAU,IAAI,MAAM,MAAM;CACjF,IAAI,OAAO,OAAO;CAClB,MAAM,OAAO,OAAO,MAAM,GAAG,EAAE,IAAI;CACnC,MAAM,UAAU,OAAO,QAAQ,OAAO,EAAE,QACrC,CAAC,UAAU,UAAU,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM,IACnD;CACA,OAAO,QAAQ,WAAW,IAAI,QAAQ,KAAK,KAAA;AAC7C;AAEA,SAAS,UAAU,MAA6B;CAC9C,MAAM,YAAY,KAAK,MAAM,MAAM,EAAE,GAAG,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY;CACtE,IAAI,cAAc,OAAO,OAAO;CAChC,IAAI,cAAc,SAAS,cAAc,QAAQ,OAAO;CACxD,IAAI,cAAc,OAAO,OAAO;CAChC,IAAI,cAAc,QAAQ,OAAO;CACjC,IAAI,cAAc,OAAO,OAAO;CAChC,OAAO;AACT;AAEA,SAAS,eAAe,OAAmB,MAA+B;CACxE,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,SAAS,IAAI,WAAW;EAC9B,OAAO,eAAe,QAAQ,OAAO,OAAO,MAAM,CAAC;EACnD,OAAO,gBAAgB,OAAO,OAAO,yBAAS,IAAI,MAAM,4BAA4B,CAAC;EACrF,OAAO,cAAc,IAAI,KAAK,CAAC,KAAiB,GAAG,EAAE,MAAM,KAAK,CAAC,CAAC;CACpE,CAAC;AACH;AAEA,SAAS,kBAAkB,MAAmC;CAC5D,MAAM,WAAW,IAAI,UAAU,EAAE,gBAAgB,MAAM,iBAAiB;CACxE,IAAI,SAAS,cAAc,aAAa,GAAG,OAAO,CAAC;CACnD,MAAM,yBAAS,IAAI,IAA+C;CAClE,MAAM,WAAW,MAAM,KAAK,SAAS,qBAAqB,GAAG,CAAC;CAC9D,KAAK,MAAM,SAAS,SAAS,QAAQ,YAAY,QAAQ,cAAc,OAAO,GAAG;EAC/E,MAAM,KAAK,MAAM,aAAa,IAAI;EAClC,MAAM,YAAY,MAAM,OAAO,WAAW;EAC1C,IAAI,CAAC,MAAM,CAAC,WAAW;EACvB,MAAM,OAAO,MAAM,WAAW,MAAM;EACpC,MAAM,OAAO,OAAO,UAAU,MAAM,MAAM,IAAI,KAAA;EAC9C,MAAM,aAAa,OAAO,UAAU,WAAW,OAAO,CAAC;EACvD,OAAO,IAAI,IAAI;GACb;GACA,GAAI,OAAO,SAAS,UAAU,KAAK,aAAa,IAAI,EAAE,OAAO,WAAW,IAAI,CAAC;EAC/E,CAAC;CACH;CAEA,OAAO,SAAS,QAAQ,YAAY,QAAQ,cAAc,WAAW,EAAE,KAAK,cAAc;EACxF,MAAM,WAAW,UAAU,WAAW,UAAU,GAAG,QAAQ,MAAM,EAAE;EACnE,MAAM,QAAQ,WAAW,OAAO,IAAI,QAAQ,IAAI,KAAA;EAChD,OAAO;GACL,MAAM,UAAU,WAAW,MAAM;GACjC,aAAa,UAAU,WAAW,aAAa;GAC/C,UAAU,OAAO;GACjB,WAAW,OAAO;EACpB;CACF,CAAC;AACH;AAEA,SAAS,YAAY,YAAmD;CACtE,MAAM,QAAQ,YAAY,QAAQ,YAAY,QAAQ,YAAY;CAClE,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;;;;;AAMA,eAAsB,kBACpB,QACA,YACA,YAC4B;CAC5B,IACE,CAAC,UACD,OAAO,WAAW,YAClB,EAAE,iBAAiB,WACnB,OAAO,OAAO,gBAAgB,YAE9B,OAAO;CAET,MAAM,OACJ,eAAe,UAAU,UAAU,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;CACrF,IAAI,QAAQ,CAAC,KAAK,YAAY,EAAE,SAAS,MAAM,GAAG,OAAO;CAEzD,IAAI;CACJ,IAAI;EACF,UAAU,UAAU,IAAI,WAAW,MAAM,OAAO,YAAY,CAAC,CAAC;CAChE,QAAQ;EACN,OAAO;CACT;CACA,MAAM,MAAM,OAAO,QAAQ,OAAO,EAAE,MAAM,CAAC,WAAW,MAAM,YAAY,EAAE,SAAS,MAAM,CAAC;CAC1F,IAAI,CAAC,KAAK,OAAO;CACjB,MAAM,WAAW,kBAAkB,IAAI,YAAY,EAAE,OAAO,IAAI,EAAE,CAAC;CACnE,IAAI,CAAC,SAAS,QAAQ,OAAO;CAE7B,MAAM,yBAAS,IAAI,IAAiC;CACpD,KAAK,MAAM,QAAQ,UAAU;EAC3B,IAAI,CAAC,KAAK,MAAM;EAChB,MAAM,QAAQ,OAAO,IAAI,KAAK,IAAI,KAAK,CAAC;EACxC,MAAM,KAAK,IAAI;EACf,OAAO,IAAI,KAAK,MAAM,KAAK;CAC7B;CAEA,MAAM,2BAAW,IAAI,IAAoC;CACzD,MAAM,eAAe,SAAiB;EACpC,MAAM,SAAS,SAAS,IAAI,IAAI;EAChC,IAAI,QAAQ,OAAO;EACnB,MAAM,WAAW,YAAY;GAC3B,MAAM,QAAQ,aAAa,SAAS,IAAI;GACxC,IAAI,CAAC,OAAO,OAAO;GACnB,MAAM,OAAO,UAAU,MAAM,EAAE;GAC/B,OAAO,OAAO,eAAe,MAAM,IAAI,IAAI,IAAI;EACjD,GAAG;EACH,SAAS,IAAI,MAAM,OAAO;EAC1B,OAAO;CACT;CAEA,MAAM,QAAQ,IACZ,WAAW,SAAS,IAAI,OAAO,SAAS,UAAU;EAChD,MAAM,aAAc,QAAQ,eAAe,CAAC;EAC5C,MAAM,YAAY,YAAY,UAAU;EACxC,MAAM,QAAQ,YAAY,OAAO,IAAI,SAAS,GAAG,MAAM,IAAI,KAAA,MAAc,SAAS;EAClF,IAAI,CAAC,MAAM;EACX,KAAK,MAAM,OAAO,OAAO,KAAK,UAAU,GAAG;GACzC,MAAM,QAAQ,IAAI,YAAY;GAC9B,KAAK,UAAU,UAAU,UAAU,kBAAkB,QAAQ,OAC3D,OAAO,WAAW;EAEtB;EACA,IAAI,KAAK,MAAM,WAAW,OAAO,KAAK;EACtC,IAAI,KAAK,aAAa,WAAW,cAAc,KAAK;EACpD,IAAI,KAAK,WAAW,WAAW,cAAc,KAAK;EAClD,IAAI,KAAK,UAAU;GACjB,MAAM,MAAM,MAAM,YAAY,KAAK,QAAQ;GAC3C,IAAI,KAAK,WAAW,YAAY;EAClC;CACF,CAAC,CACH;CACA,OAAO;AACT;AAEA,SAAS,SAAS,OAAuB;CACvC,IAAI,OAAO;CACX,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GACjD,OAAO,KAAK,KAAK,OAAO,MAAM,WAAW,KAAK,GAAG,QAAQ;CAE3D,QAAQ,SAAS,GAAG,SAAS,EAAE;AACjC;;;;;AAMA,eAAsB,gBACpB,KAIA,YAC2B;CAC3B,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,WAAW,WAAW,UAAU;EACzC,MAAM,QAAQ,QAAQ,aAAa;EACnC,IAAI,OAAO,UAAU,UAAU,KAAK,IAAI,KAAK;CAC/C;CACA,IAAI,CAAC,KAAK,MAAM,OAAO;CAEvB,MAAM,UAAqB,CAAC;CAC5B,MAAM,QAAQ,IACZ,MAAM,KAAK,IAAI,EAAE,KACd,QACC,IAAI,SAAe,YAAY;EAC7B,MAAM,KAAK,uBAAuB,SAAS,GAAG;EAC9C,QAAQ,KAAK,KAAK,EAAE;EACpB,IAAI,IAAI,SAAS,EAAE,GAAG;GACpB,QAAQ;GACR;EACF;EACA,MAAM,QAAQ,IAAI,MAAM;EACxB,MAAM,eAAe;GAGnB,IAAI,CAAC,IAAI,SAAS,EAAE,GAAG,IAAI,SAAS,IAAI,OAAO,EAAE,YAAY,EAAE,CAAC;GAChE,QAAQ;EACV;EACA,MAAM,gBAAgB,QAAQ;EAC9B,MAAM,MAAM;CACd,CAAC,CACL,CACF;CACA,OAAO;EAAC;EAAS,CAAC,OAAO,QAAQ;EAAG,GAAG;EAAS;CAAE;AACpD;;;;;;ACjOA,IAAa,yBAAkD;CAC7D,cAAc;CACd,UAAU,KAAK,OAAO;AACxB;;;;;;;;;;;AA8BA,SAAgB,iBAAiB,QAA+C;CAC9E,MAAM,EACJ,WACA,aACA,cACA,UACA,WACA,iBAAiB,SACf;CAEJ,MAAM,OAAO,aAAa,cAAc,SAAS,YAAa,eAAe;CAE7E,IAAI,SAAS,WAAW,OAAO;CAC/B,IAAI,SAAS,SAAS,OAAO,iBAAiB,UAAU;CAExD,IAAI,CAAC,gBAAgB,OAAO;CAE5B,MAAM,SAAS;EAAE,GAAG;EAAwB,GAAG;CAAU;CACzD,MAAM,kBAAkB,iBAAiB,KAAA,KAAa,eAAe,OAAO;CAC5E,MAAM,WAAW,aAAa,KAAA,KAAa,WAAW,OAAO;CAE7D,OAAO,mBAAmB,WAAW,UAAU;AACjD;;;;;;AC5CA,IAAa,gBAAkC;CAC7C,WAAW;CACX,aAAa;CACb,WAAW;CACX,WAAW;CACX,aAAa;CACb,cAAc;CACd,eAAe;CACf,WAAW;CACX,eAAe;CACf,kBAAkB;CAClB,eAAe;CACf,gBAAgB;AAClB;AAGA,IAAM,gBAAoD;CACxD;CACA,CAAC,QAAQ;CACT,CAAC,iBAAiB;CAClB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAGA,IAAM,iBAAqD;CACzD;CACA,CAAC,OAAO,aAAa;CACrB;CACA;CACA;CACA;CACA;AACF;;AAqCA,SAAgB,YAAY,OAA2D;CACrF,OAAO,MAAM,aAAa;AAC5B;;;;;;;AAQA,SAAgB,UAAU,OAAkC;CAC1D,OAAO,OAAO,MAAM,eAAe,YAAY,MAAM,WAAW,KAAK,EAAE,SAAS;AAClF;;;;;;;;;;AAWA,SAAgB,eAAe,OAA6D;CAC1F,OAAO,CACL,aACA;EAAC;EAAY,CAAC,OAAO,MAAM,cAAc,EAAE;EAAG;CAAE,CAClD;AACF;;;;;;;;AASA,SAAgB,iBACd,OACA,SACyB;CACzB,MAAM,eAAe,MAAM,qBAAqB;CAChD,OAAO;EACL,YAAY,UAAU,YAAY;EAClC,cAAc,eAAe,KAAK;EAClC,aAAa,MAAM,aAAA;EACnB,oBAAoB,MAAM,mBAAmB,SAAS,SAAS;EAC/D,sBAAsB;EACtB,yBAAyB;CAC3B;AACF;;;;;;;;AASA,SAAgB,WAAW,SAAiB,QAA6B;CACvE,OAAO,GAAG,QAAQ,GAAG;AACvB;;;;;;;AAQA,SAAgB,aAAa,SAAyB;CACpD,IAAI,CAAC,OAAO,SAAS,OAAO,GAAG,OAAO;CACtC,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC;AACzC;;;;;;;;;AAUA,SAAgB,WACd,QACA,OACA,UAAU,GACkB;CAC5B,MAAM,SAAS,aAAa,OAAO;CAGnC,MAAM,YAAY,MAAM,uBAAuB,MAAM;CACrD,MAAM,YAAY,MAAM,uBAAuB,MAAM;CACrD,MAAM,cAAc,MAAM,yBAAyB,MAAM;CACzD,QAAQ,QAAR;EACE,KAAK,QACH,OAAO;GACL,cAAc;GACd,gBAAgB,MAAM,cAAc;EACtC;EACF,KAAK,aACH,OAAO;GAGL,wBACE,MAAM,4BAA4B,MAAM,kBAAkB;GAC5D,2BAA2B,MAAM,oBAAoB,KAAK;GAG1D,yBAAyB,MAAM,mBAAmB;GAClD,uBAAuB,MAAM,iBAAiB;EAChD;EACF,KAAK,WACH,OAAO;GACL,cAAc;GACd,cAAc,MAAM;GACpB,gBAAgB;EAClB;EACF,KAAK,QACH,OAAO;GACL,cAAc;GACd,cAAc,MAAM;GACpB,gBAAgB;EAClB;EACF,KAAK,UACH,OAAO;GACL,gBAAgB;GAChB,iBAAiB,MAAM;GACvB,kBAAkB,MAAM,gBAAgB;GACxC,uBAAuB;GACvB,uBAAuB;GACvB,yBAAyB;EAC3B;EACF,KAAK,WACH,OAAO;GACL,kBAAkB,MAAM,iBAAiB;GACzC,qBAAqB,MAAM,oBAAoB;GAC/C,mBAAmB;GACnB,iBAAiB;EACnB;EACF,KAAK,WACH,OAAO;GAGL,gBAAgB;GAChB,iBAAiB;GACjB,kBAAkB,MAAM,gBAAgB;GACxC,uBAAuB;GACvB,uBAAuB;GACvB,yBAAyB;EAC3B;EACF,KAAK,iBACH,OAAO;GACL,cAAc;GACd,gBAAgB;EAClB;EACF,KAAK,SACH,OAAO;GACL,cAAc,MAAM,cAAA;GACpB,mBAAmB,MAAM,kBAAA;GACzB,mBAAmB,KAAK,IAAI,GAAG,MAAM,kBAAA,CAA0C;GAC/E,gBAAgB;EAClB;CACJ;AACF;;;;;;;;;;;;;AAcA,SAAgB,qBACd,MACA,OACA,UAAU,GACC;CACX,MAAM,SAAS,aAAa,OAAO;CACnC,MAAM,MAAiB,CAAC;CACxB,MAAM,OAAO,WAAwB,KAAK,SAAS,SAAS,WAAW,KAAK,IAAI,MAAM,CAAC;CACvF,MAAM,QAAQ,QAAqB,UAAkB,UAAkC;EACrF,IAAI,UAAU,KAAA,KAAa,IAAI,MAAM,GACnC,IAAI,KAAK;GAAE,SAAS,WAAW,KAAK,IAAI,MAAM;GAAG;GAAU;EAAM,CAAC;CAEtE;CAGA,MAAM,YAAY,MAAM,uBAAuB,MAAM;CACrD,MAAM,YAAY,MAAM,uBAAuB,MAAM;CACrD,MAAM,cAAc,MAAM,yBAAyB,MAAM;CAEzD,KAAK,QAAQ,cAAc,SAAS;CACpC,KAAK,QAAQ,gBAAgB,MAAM,gBAAgB,KAAA,IAAY,KAAA,IAAY,MAAM,cAAc,MAAM;CAKrG,KAAK,aAAa,wBAAwB,MAAM,4BAA4B,MAAM,cAAc;CAChG,KACE,aACA,0BACA,MAAM,qBAAqB,KAAA,IAAY,KAAA,IAAY,MAAM,mBAAmB,MAC9E;CACA,KAAK,aAAa,yBAAyB,MAAM,eAAe;CAChE,KAAK,aAAa,uBAAuB,MAAM,aAAa;CAC5D,KAAK,WAAW,cAAc,SAAS;CACvC,KAAK,WAAW,cAAc,MAAM,SAAS;CAC7C,KAAK,QAAQ,cAAc,SAAS;CACpC,KAAK,QAAQ,cAAc,MAAM,SAAS;CAC1C,KAAK,UAAU,gBAAgB,WAAW;CAC1C,KAAK,UAAU,iBAAiB,MAAM,YAAY;CAClD,KAAK,UAAU,kBAAkB,MAAM,kBAAkB,KAAA,IAAY,KAAA,IAAY,MAAM,gBAAgB,MAAM;CAI7G,KAAK,WAAW,kBAAkB,MAAM,aAAa;CACrD,KAAK,WAAW,qBAAqB,MAAM,gBAAgB;CAC3D,KAAK,WAAW,gBAAgB,WAAW;CAC3C,KAAK,WAAW,kBAAkB,MAAM,kBAAkB,KAAA,IAAY,KAAA,IAAY,MAAM,gBAAgB,MAAM;CAI9G,KAAK,SAAS,cAAc,MAAM,UAAU;CAC5C,KAAK,SAAS,mBAAmB,MAAM,cAAc;CACrD,KACE,SACA,mBACA,MAAM,mBAAmB,KAAA,IAAY,KAAA,IAAY,KAAK,IAAI,GAAG,MAAM,cAAc,CACnF;CAEA,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,kBACd,MACA,OACA,SACW;CACX,MAAM,SAAS,aAAa,OAAO;CACnC,MAAM,MAAiB,CAAC;CACxB,MAAM,OAAO,WAAwB,KAAK,SAAS,SAAS,WAAW,KAAK,IAAI,MAAM,CAAC;CACvF,MAAM,QAAQ,QAAqB,UAAkB,UAA2B;EAC9E,IAAI,IAAI,MAAM,GACZ,IAAI,KAAK;GAAE,SAAS,WAAW,KAAK,IAAI,MAAM;GAAG;GAAU;EAAM,CAAC;CAEtE;CAEA,KAAK,QAAQ,gBAAgB,MAAM,cAAc,MAAM;CACvD,KAAK,aAAa,2BAA2B,MAAM,oBAAoB,KAAK,MAAM;CAClF,KAAK,WAAW,gBAAgB,MAAM;CACtC,KAAK,QAAQ,gBAAgB,MAAM;CACnC,KAAK,UAAU,kBAAkB,MAAM,gBAAgB,MAAM;CAC7D,KAAK,UAAU,yBAAyB,MAAM;CAC9C,KAAK,WAAW,mBAAmB,MAAM;CACzC,KAAK,WAAW,kBAAkB,MAAM,gBAAgB,MAAM;CAC9D,KAAK,WAAW,yBAAyB,MAAM;CAC/C,KAAK,iBAAiB,gBAAgB,MAAM;CAC5C,KAAK,SAAS,gBAAgB,MAAM;CAEpC,OAAO;AACT;;;;;;;;;AAUA,SAAgB,WACd,KACA,MACA,OACA,UAAU,GACJ;CACN,KAAK,MAAM,MAAM,qBAAqB,MAAM,OAAO,OAAO,GACxD,IAAI,iBAAiB,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK;AAE1D;;;;;;;;;AAUA,SAAgB,aACd,KACA,MACA,OACA,SACM;CACN,KAAK,MAAM,MAAM,kBAAkB,MAAM,OAAO,OAAO,GACrD,IAAI,iBAAiB,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK;AAE1D;;;;;;;;;ACrYA,SAAgB,YAAY,SAAyB;CACnD,OAAO,GAAG,QAAQ;AACpB;;;;;;;;;;;;;;;AAgBA,SAAgB,oBACd,UACA,UAAU,OACQ;CAClB,QAAQ,UAAR;EACE,KAAK,WACH,OAAO,UAAU,CAAC,WAAW,IAAI,CAAC,QAAQ,SAAS;EACrD,KAAK,QACH,OAAO,CAAC,MAAM;EAChB,KAAK,SACH,OAAO,CAAC,QAAQ;EAClB,SACE,OAAO,UAAU;GAAC;GAAa;GAAQ;EAAQ,IAAI;GAAC;GAAQ;GAAW;GAAQ;EAAQ;CAC3F;AACF;AAEA,IAAM,eAAsF;CAC1F,MAAM;CACN,WAAW;CACX,SAAS;CACT,MAAM;CACN,QAAQ;AACV;AAEA,IAAM,iBAA8D;CAClE,MAAM;EAAC;EAAM,CAAC,eAAe;EAAG;CAAS;CACzC,WAAW;EAAC;EAAM,CAAC,eAAe;EAAG;CAAS;CAC9C,SAAS;EAAC;EAAM,CAAC,eAAe;EAAG;CAAS;CAC5C,MAAM;EAAC;EAAM,CAAC,eAAe;EAAG;CAAY;CAC5C,QAAQ;EAAC;EAAM,CAAC,eAAe;EAAG;CAAO;AAC3C;AAEA,IAAM,eAAoC;CAAC;CAAM,CAAC,eAAe;CAAG;AAAO;AAC3E,IAAM,iBAAsC,CAAC,OAAO,aAAa;AACjE,IAAM,qBAA0C,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC;;;;;;;;;;AAiC5E,SAAgB,iBACd,KACA,SACA,MACA,aACA,SACQ;CACR,MAAM,WAAW,YAAY,OAAO;CACpC,MAAM,OAA4B;EAAE,MAAM;EAAW;CAAK;CAC1D,IAAI,aAAa,KAAK,cAAc;CACpC,IAAI,SAAS;EACX,KAAK,UAAU;EACf,KAAK,gBAAgB,QAAQ;EAC7B,KAAK,iBAAiB,QAAQ;CAChC;CACA,IAAI,UAAU,UAAU,IAAI;CAC5B,OAAO;AACT;;;;;;;;;;;AAYA,SAAgB,kBACd,cACA,OACA,aACiD;CACjD,IAAI,eAAe,iBAAiB,SAAS,OAAO,KAAA;CACpD,IAAI,YAAY,KAAK,MAAM,WAAW,OAAO,KAAA;CAC7C,OAAO;EAAE,QAAQ,MAAM,iBAAiB;EAAI,SAAS,MAAM,kBAAkB;CAAG;AAClF;;;;;;;;;AAwBA,SAAgB,oBACd,KACA,SACA,SACQ;CACR,MAAM,WAAW,YAAY,OAAO;CACpC,MAAM,OAA4B;EAChC,MAAM;EACN,OAAO,CAAC,QAAQ,OAAO;EACvB,SAAS;EACT,SAAS,QAAQ;CACnB;CACA,IAAI,QAAQ,QAAQ,KAAK,SAAS,QAAQ;CAC1C,IAAI,QAAQ,aAAa,KAAK,cAAc,QAAQ;CACpD,IAAI,UAAU,UAAU,IAAI;CAC5B,OAAO;AACT;;;;;;;;AASA,SAAgB,kBAAkB,KAAkB,SAAqC;CACvF,MAAM,EAAE,SAAS,cAAc,OAAO,SAAS,SAAS,aAAa,UAAU,iBAC7E;CACF,MAAM,WAAW,YAAY,OAAO;CACpC,MAAM,SAAS,EAAE,YAAY,UAAU,YAAY,OAAO;CAI1D,MAAM,SAAS,YAAY,IAAI,SAAS,QAAQ,IAAI,WAAW,KAAA;CAE/D,MAAM,OAAO,IAAY,SAA0C;EAEjE,IAAI,SAAS;GAAE;GAAI,QAAQ;GAAU;GAAQ,GAAG;EAAK,GAAU,MAAM;EACrE,OAAO;CACT;CAIA,MAAM,YAAY,CAAC,eAAe,iBAAiB,UAAU,YAAY,KAAK,IAAI;CAKlF,MAAM,aAAa,QAA4B;EAC7C,IAAI,UAAU,KAAK,GACjB,IAAI,KAAK,cAAc,KAAK;GAAE;GAAS;GAAO;GAAS;GAAS;GAAa;EAAS,CAAC,CAAC;EAE1F,OAAO;CACT;CAEA,IAAI,cAAc,WAChB,OAAO,UAAU,CACf,IAAI,WAAW,SAAS,SAAS,GAAG;EAClC,MAAM;EACN,QAAQ;EACR,OAAO,WAAW,WAAW,OAAO,OAAO;CAC7C,CAAC,CACH,CAAC;CAGH,IAAI,cAAc,WAChB,OAAO,UAAU;EACf,IAAI,WAAW,SAAS,SAAS,GAAG;GAClC,MAAM;GACN,QAAQ;GACR,OAAO,WAAW,WAAW,OAAO,OAAO;EAC7C,CAAC;EACD,IAAI,WAAW,SAAS,eAAe,GAAG;GACxC,MAAM;GACN,QAAQ;GACR,QAAQ;IACN,GAAG;IACH,cAAc,CAAC,OAAO,yBAAyB;IAC/C,aAAa;IACb,sBAAsB;IACtB,yBAAyB;GAC3B;GACA,OAAO,WAAW,iBAAiB,OAAO,OAAO;EACnD,CAAC;EACD,IAAI,WAAW,SAAS,QAAQ,GAAG;GACjC,MAAM;GACN,QAAQ;GACR,OAAO,WAAW,UAAU,OAAO,OAAO;EAC5C,CAAC;CACH,CAAC;CAGH,MAAM,MAAM,oBAAoB,cAAc,MAAM,qBAAqB,IAAI,EAAE,KAAK,WAChF,IAAI,WAAW,SAAS,MAAM,GAAG;EAC/B,MAAM,aAAa;EACnB,GAAI,cAAc,EAAE,gBAAgB,YAAY,IAAI,CAAC;EACrD,QACE,WAAW,YAAY,eACnB;GAAC;GAAO,eAAe;GAAQ,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC;EAAC,IACxE,eAAe;EACrB,OAAO,WAAW,QAAQ,OAAO,OAAO;CAC1C,CAAC,CACH;CACF,IAAI,iBAAiB,WAAW,cAC9B,IAAI,KACF,IAAI,GAAG,QAAQ,YAAY;EACzB,MAAM;EACN,QAAQ;GAAC;GAAO;GAAc,CAAC,OAAO,yBAAyB;EAAC;EAChE,QAAQ;GACN,GAAG;GACH,cAAc;GACd,aAAa;GACb,sBAAsB;GACtB,yBAAyB;EAC3B;EACA,OAAO,EAAE,gBAAgB,QAAQ;CACnC,CAAC,CACH;CAEF,OAAO,UAAU,GAAG;AACtB;;;;;;;;;AA4BA,SAAgB,cAAc,KAAkB,SAAuC;CACrF,MAAM,EAAE,SAAS,OAAO,SAAS,SAAS,aAAa,aAAa;CACpE,MAAM,KAAK,WAAW,SAAS,OAAO;CACtC,MAAM,SAAS,YAAY,IAAI,SAAS,QAAQ,IAAI,WAAW,KAAA;CAC/D,IAAI,SACF;EACE;EACA,MAAM;EACN,QAAQ,YAAY,OAAO;EAC3B,GAAI,cAAc,EAAE,gBAAgB,YAAY,IAAI,CAAC;EACrD,QAAQ,iBAAiB,OAAO,OAAO;EACvC,OAAO,WAAW,SAAS,OAAO,OAAO;CAE3C,GACA,MACF;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,oBACd,KACA,UACA,SACM;CACN,KAAK,MAAM,MAAM,UAIf,IAAI,IAAI,SAAS,EAAE,GACjB,IAAI,kBAAkB,IAAI,cAAc,UAAU,YAAY,MAAM;AAG1E;;;;;;;;AASA,SAAgB,sBACd,KACA,UACA,UACM;CACN,KAAK,MAAM,MAAM,UACf,IAAI,IAAI,SAAS,EAAE,GAAG,IAAI,YAAY,EAAE;CAE1C,IAAI,IAAI,UAAU,QAAQ,GAAG,IAAI,aAAa,QAAQ;AACxD;;;AC9UA,IAAI;;;;;;AAOJ,SAAgB,cAAuC;CACrD,IAAI,CAAC,eAAe;EAClB,MAAM,iBAAkB,WAAuC;EAG/D,IAAI,kBAAkB,OAAO,eAAe,gBAAgB,YAC1D,gBAAgB,QAAQ,QAAQ,cAAc;OAE9C,gBAAgB,OAAO,eAAe,MACnC,WAAY,OAAO,WAAW,MACjC;EAEF,cAAc,YAAY;GACxB,gBAAgB,KAAA;EAClB,CAAC;CACH;CACA,OAAO;AACT;;;;;;ACvDA,IAAa,gBAAgB;AAY7B,IAAM,4BAAY,IAAI,IAA0B;AAChD,IAAI,qBAAqB;;;;;;;;;;AAWzB,SAAgB,WAAW,aAA6B;CACtD,OAAO,GAAG,cAAc,KAAK,mBAAmB,WAAW,EAAE;AAC/D;;;;;;;AAkBA,SAAgB,aAAa,KAAmC;CAC9D,MAAM,QAAQ,IAAI,OAAO,IAAI,cAAc,4CAA4C,EAAE,KACvF,GACF;CACA,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO;EACL,aAAa,mBAAmB,MAAM,EAAE;EACxC,GAAG,OAAO,MAAM,EAAE;EAClB,GAAG,OAAO,MAAM,EAAE;EAClB,GAAG,OAAO,MAAM,EAAE;CACpB;AACF;;;;;;;;;;;AAYA,eAAsB,SAAS,KAAa,QAA0C;CACpF,MAAM,SAAS,aAAa,GAAG;CAC/B,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,WAAW,cAAc,gBAAgB,KAAK;CAGhE,MAAM,WAAW,UAAU,IAAI,OAAO,WAAW;CACjD,IAAI,CAAC,UAAU,OAAO,IAAI,WAAW,CAAC;CAEtC,OAAO,SAAS,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM;AACtD;;;;;;;;;;;;;;AAeA,eAAsB,qBACpB,aACA,UACe;CACf,UAAU,IAAI,aAAa,QAAQ;CACnC,IAAI,CAAC,oBAAoB;EACvB,MAAM,MAAM,MAAM,YAAY;EAC9B,IAAI,CAAC,oBAAoB;GACvB,IAAI,YAAY,eAAe,OAAO,QAAQ,oBAAoB;IAEhE,OAAO,EAAE,MAAA,MADU,SAAS,OAAO,KAAK,gBAAgB,MAAM,EAChD;GAChB,CAAC;GACD,qBAAqB;EACvB;CACF;AACF;;;;;;;AAQA,SAAgB,uBAAuB,aAA2B;CAChE,UAAU,OAAO,WAAW;CAC5B,IAAI,UAAU,SAAS,KAAK,oBAC1B,YAAiB,EACd,MAAM,QAAQ;EAEb,IAAI,UAAU,SAAS,KAAK,oBAAoB;GAC9C,IAAI,eAAe,aAAa;GAChC,qBAAqB;EACvB;CACF,CAAC,EACA,YAAY,CAEb,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9FA,IAAM,wBAAwB;;AAG9B,IAAM,YAAY;;;;;;;;;;;AAYlB,IAAM,+BAA+B;;AAGrC,SAAS,UAAU,UAA0B;CAC3C,MAAM,UAAU,KAAK,IAAI,uBAAuB,KAAK,IAAI,YAAwB,QAAQ,CAAC;CAC1F,OAAO,KAAM,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAK,UAAU,KAAK,KAAM,GAAG,CAAC,KAAK,IAAI,KAAK;AACvF;;;;;;;;;;;AAYA,SAAgB,cAAc,MAAc,MAAsB;CAChE,MAAM,OAAO,OAAO;CACpB,IAAI,QAAQ,KAAK,OAAO;CACxB,QAAS,OAAO,MAAO,OAAO;AAChC;;;;;;;;;;;AAYA,SAAgB,gBACd,MACA,UACA,SACoB;CACpB,IAAI,CAAC,KAAK,OAAO,UAAU,OAAO,SAAS,KAAK,CAAC,GAAG,OAAO,KAAA;CAC3D,MAAM,CAAC,MAAM,OAAO,MAAM,SAAS;CACnC,MAAM,cAAc,SAAS,QAAQ,IAAI;CACzC,MAAM,eAAe,SAAS,SAAS,IAAI;CAC3C,IAAI,EAAE,cAAc,MAAM,EAAE,eAAe,IAAI,OAAO,KAAA;CAItD,MAAM,iBAAiB,cAAc,MAAM,IAAI,IAAI;CACnD,MAAM,iBAAiB,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,KAAK,CAAC;CAEnE,MAAM,SAAmB,CAAC;CAC1B,IAAI,iBAAiB,GAAG,OAAO,KAAK,eAAe,YAAY,eAAe;CAC9E,IAAI,iBAAiB,GAAG,OAAO,KAAK,gBAAgB,YAAY,eAAe;CAC/E,IAAI,OAAO,WAAW,GAAG,OAAO,KAAA;CAEhC,MAAM,OAAO,KAAK,KAAK,KAAK,IAAI,GAAG,MAAM,CAAC;CAC1C,OAAO,OAAO,SAAS,IAAI,IAAI,OAAO,KAAA;AACxC;;;;;;;AAkBA,SAAS,WAAW,KAAiE;CACnF,MAAM,SAAS,OAAO,IAAI,cAAc,aAAa,IAAI,UAAU,IAAI,KAAA;CACvE,MAAM,QAAQ,QAAQ,eAAe;CACrC,MAAM,SAAS,QAAQ,gBAAgB;CACvC,OAAO,QAAQ,KAAK,SAAS,IAAI;EAAE;EAAO;CAAO,IAAI,KAAA;AACvD;;;;;AAMA,SAAS,WACP,KACA,MACA,SACoB;CACpB,MAAM,CAAC,QAAQ,QAAQ;CAKvB,IAHE,CAAC,OAAO,SAAS,IAAI,KACrB,CAAC,OAAO,SAAS,IAAI,KACrB,cAAc,MAAM,IAAI,KAAK,8BACb,OAAO,QAAQ;CAEjC,MAAM,WAAW,WAAW,GAAG;CAC/B,MAAM,WAAW,WAAW,gBAAgB,MAAM,UAAU,QAAQ,OAAO,IAAI,KAAA;CAC/E,IAAI,aAAa,KAAA,GAAW,OAAO,QAAQ;CAC3C,OAAO,KAAK,IAAI,UAAU,QAAQ,WAAW,OAAO,iBAAiB;AACvE;;;;;;;;;AAUA,SAAgB,aAAa,KAAkB,MAAY,SAA+B;CACxF,MAAM,UAAU,WAAW,KAAK,MAAM,OAAO;CAE7C,IAAI,UACF,CACE,CAAC,KAAK,IAAI,KAAK,EAAE,GACjB,CAAC,KAAK,IAAI,KAAK,EAAE,CACnB,GACA;EACE,SAAS,QAAQ;EACjB,GAAI,QAAQ,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,QAAQ,SAAS;EACvE,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ;CAC7C,CACF;AACF;;;;;;;;;;;;;;;;;;ACvKA,SAAgB,MAAM,OAAe,KAAa,KAAqB;CACrE,OAAO,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,GAAG;AAC3C;;;;;;;;;;;;;;;AAgBA,SAAgB,mBAAmB,OAAe,MAAsB;CACtE,IAAI,SAAS,GAAG,OAAO,MAAM,SAAS;CACtC,MAAM,WAAW,KAAK,IAAI,GAAG,CAAC,KAAK,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC;CAC1D,OAAO,MAAM,QAAQ,QAAQ;AAC/B;;;;;;;;;;;;;AAcA,SAAgB,WAAW,QAAyB;CAClD,MAAM,KAAK,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC;CACpD,OAAO,SAAS,GAAG,OAAO,GAAG,OAAO;AACtC;;;;;;;;;;;;;;AAeA,SAAgB,SACd,IACA,OACkC;CAClC,IAAI,YAAkD;CAEtD,QAAQ,GAAG,SAAwB;EACjC,IAAI,WACF,aAAa,SAAS;EAExB,YAAY,iBAAiB;GAC3B,GAAG,GAAG,IAAI;GACV,YAAY;EACd,GAAG,KAAK;CACV;AACF;;;;;;;;;;;;;;AAeA,SAAgB,SACd,IACA,OACkC;CAClC,IAAI,aAAa;CAEjB,QAAQ,GAAG,SAAwB;EACjC,IAAI,CAAC,YAAY;GACf,GAAG,GAAG,IAAI;GACV,aAAa;GACb,iBAAiB;IACf,aAAa;GACf,GAAG,KAAK;EACV;CACF;AACF;;;;;;;;;;;;;AAcA,SAAgB,WAAW,SAA0C;CACnE,OAAO,OAAO,QAAQ,OAAO,EAC1B,QAAQ,GAAG,WAAW,KAAK,EAC3B,KAAK,CAAC,SAAS,GAAG,EAClB,KAAK,GAAG;AACb;;;;;;;;;;;;;;;ACxHA,IAAa,wBAAwB,KAAK,KAAK;AAE/C,IAAM,wBAAQ,IAAI,IAAgC;;;;;;;;AASlD,eAAsB,gBAAgB,KAA0C;CAC9E,IAAI,CAAC,gBAAgB,KAAK,GAAG,GAAG,OAAO,KAAA;CACvC,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG;EACnB,IAAI;EACJ,IAAI;GAEF,MAAM,UAAS,MADQ,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,GAC5B,QAAQ,IAAI,gBAAgB;GACpD,IAAI,QAAQ,OAAO,OAAO,MAAM;EAClC,QAAQ,CAER;EACA,MAAM,IAAI,KAAK,IAAI;CACrB;CACA,OAAO,MAAM,IAAI,GAAG;AACtB;;;;;;;;;AAUA,eAAsB,0BAA0B,KAA0C;CACxF,MAAM,OAAO,MAAM,gBAAgB,GAAG;CACtC,IAAI,SAAS,KAAA,KAAa,OAAO,uBAAuB;EACtD,MAAM,OAAO,OAAO,QAAQ,GAAG,QAAQ,CAAC;EACxC,MAAM,IAAI,MACR,gBAAgB,IAAI,uHAEtB;CACF;CACA,OAAO;AACT;;;AC8CA,IAAM,wBAAwB;;;;;;;AAQ9B,SAAgB,aAAa,SAAyB;CACpD,OAAO,KAAK,UAAU,QAAQ,kBAAkB,GAAG;AACrD;;;;;;;;;;;;AAaA,SAAgB,eACd,QACA,YACwB;CACxB,IAAI,OAAO,WAAW,UACpB,OAAO;EAAE,MAAM;EAAO,KAAK;CAAO;CAEpC,MAAM,OAAO,YAAY,KAAK,IAAI,aAAa,KAAA;CAC/C,IAAI,OAAO,SAAS,eAAe,kBAAkB,MACnD,OAAO;EAAE,MAAM;EAAQ,UAAU,OAAO;EAAM,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CAAG;CAE1E,IAAI,OAAO,SAAS,eAAe,kBAAkB,MACnD,OAAO;EAAE,MAAM;EAAQ,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;CAAG;CAEnD,OAAO,EAAE,MAAM,UAAU;AAC3B;;;;;;;;;;;;;;;AAgBA,SAAgB,gCACd,QACA,SACS;CACT,IAAI,OAAO,SAAS,eAAe,EAAE,kBAAkB,OAAO,OAAO;CACrE,IAAI,CAAC,UAAU,KAAK,OAAO,IAAI,GAAG,OAAO;CACzC,MAAM,aAAa,IAAI,KACpB,QAAQ,kBAAkB,CAAC,GAAG,KAAK,SAClC,KAAK,KAAK,MAAM,KAAK,KAAK,YAAY,GAAG,IAAI,CAAC,EAAE,YAAY,CAC9D,CACF;CACA,OAAO,CAAC,WAAW,IAAI,KAAK,KAAK,CAAC,WAAW,IAAI,KAAK;AACxD;;;;;;;AAQA,IAAa,eAAb,MAA0B;;;;;CAKxB,oCAAqC,IAAI,QAAwB;CACjE;CACA;CACA;CACA;CACA,2BAAmB,IAAI,IAAyB;CAChD;CACA;CACA,gBAAwB;CACxB;CAGA,+BAAuB,IAAI,IAAuB;;;;;;CAOlD,YAAY,MAAwB;EAClC,KAAK,OAAO,KAAK;EACjB,KAAK,WAAW,KAAK;EACrB,KAAK,QAAQ,KAAK;EAClB,KAAK,aAAa,KAAK;CACzB;;;;CAKA,YAA+B;EAC7B,OAAO,MAAM,KAAK,KAAK,SAAS,OAAO,IAAI,YAAY,EAAE,GAAG,OAAO,KAAK,EAAE;CAC5E;;;;;;CAOA,SAAS,IAAyC;EAChD,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,OAAO,SAAS,EAAE,GAAG,OAAO,KAAK,IAAI,KAAA;CACvC;;;;;;CAOA,MAAM,gCAA+C;EACnD,KAAK,MAAM,UAAU,KAAK,SAAS,OAAO,GAAG;GAC3C,MAAM,eAAe,QAAQ,KAAK,KAAK,UAAU,OAAO,KAAK,QAAQ,CAAC;GACtE,MAAM,cAAc,OAAO,KAAK,SAAS,OAAO,OAAO,QAAQ,KAAK,KAAK,SAAS,EAAE,CAAC,CAAC;GACtF,IAAI,gBAAgB,aAAa;GAEjC,KAAK,cAAc,MAAM;GACzB,IAAI,cAAc;IAChB,KAAK,MAAM,MAAM,OAAO,KAAK,UAC3B,IAAI,KAAK,KAAK,SAAS,EAAE,GAAG,KAAK,KAAK,YAAY,EAAE;IAEtD,OAAO,KAAK,WAAW,kBAAkB,KAAK,MAAM;KAClD,SAAS,OAAO,KAAK;KACrB,cAAc,OAAO,KAAK;KAC1B,OAAO,OAAO,KAAK;KACnB,SAAS,OAAO,KAAK;KACrB,SAAS,OAAO,KAAK;KACrB,aAAa,OAAO,KAAK,eAAe,UAAU,OAAO,KAAK,KAAK,KAAA;KACnE,UACE,OAAO,KAAK,YAAY,KAAK,KAAK,SAAS,OAAO,KAAK,QAAQ,IAC3D,OAAO,KAAK,WACZ,KAAA;IACR,CAAC;IACD,KAAK,cAAc,MAAM;IACzB,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;IACxD;GACF;GACA,OAAO,KAAK,WAAW,CAAC;GACxB,IAAI,OAAO,KAAK,eAAe,SAC7B,MAAM,KAAK,cAAc,MAAM;QAE/B,MAAM,KAAK,gBAAgB,MAAM;GAEnC,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;EAC1D;CACF;;;;;;;;;;;;;CAcA,MAAM,gBAAgB,IAA+C;EACnE,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ,OAAO;EACpB,IAAI,OAAO,SACT,OAAO,kBACL,OAAO,QACP,OAAO,SACP,OAAO,aACJ,OAAO,KAAK,OAAO,SAAS,SAAS,OAAO,KAAK,OAAO,WAAW,KAAA,EACxE;EAEF,IAAI,OAAO,WAAW;GACpB,MAAM,SAAS,MAAM,KAAK,WAAW;GACrC,OAAO,kBACL,OAAO,QACP,MAAM,OAAO,cAAc,OAAO,SAAS,GAC3C,OAAO,aACJ,OAAO,KAAK,OAAO,SAAS,SAAS,OAAO,KAAK,OAAO,WAAW,KAAA,EACxE;EACF;EAKA,MAAM,QAFS,KAAK,KAAK,UAAU,OAAO,KAAK,QAC5B,GAAQ,UAAU,IACZ;EACzB,IAAI,QAAQ,OAAO,SAAS,YAAa,KAA2B,MAClE,OAAO;EAET,OAAO;CACT;;;;;;;;;;CAWA,MAAM,uBAAuB,IAAY,UAA6C;EACpF,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,UAAU,CAAC,OAAO,KAAK,QAAQ,SAAS,QAAQ,GAAG,OAAO;EAC/D,IAAI,OAAO,WAET,QAAO,MADc,KAAK,WAAW,GACvB,kBAAkB,OAAO,WAAW,QAAQ;EAE5D,MAAM,aAAa,MAAM,KAAK,gBAAgB,EAAE;EAChD,IAAI,CAAC,YAAY,OAAO;EACxB,OAAO,WAAW,SACf,KAAK,YAAY,QAAQ,aAAa,SAAS,EAC/C,QAAQ,UAAU,UAAU,QAAQ,UAAU,KAAA,CAAS;CAC5D;;;;;;;;CASA,MAAM,QACJ,QACA,UAA8B,CAAC,GACL;EAC1B,MAAM,WAAW,aAAa,QAAQ,QAAQ,MAAM;EACpD,MAAM,KAAK,QAAQ,MAAM,WAAW,QAAQ;EAC5C,IAAI,KAAK,SAAS,IAAI,EAAE,GACtB,MAAM,IAAI,MAAM,UAAU,GAAG,iBAAiB;EAEhD,IAAI,YACF,OAAO,WAAW,YAAY,WAAW,OACrC,KAAK,kBAAkB,IAAI,MAAgB,IAC3C,KAAA;EACN,IACE,OAAO,WAAW,YAClB,gBAAgB,KAAK,MAAM,KAC3B,KAAK,SAAS,WACd;GACA,YAAY;GACZ,KAAK,MAAM,WAAW,EAAE,SAAS,eAAe,SAAS,KAAK,KAAK,CAAC;GACpE,IAAI;IACF,MAAM,SAAS,MAAM,KAAK,SAAS,UAAU,MAAM;IACnD,IAAI,CAAC,QACH,YAAY,KAAA;SACP;KACL,MAAM,YAAY,iCAAiC,KAAK,OAAO,IAAI;KACnE,IAAI,SAAS,WAAW,aAAa,WAAW,SAAS,SAAS;KAClE,MAAM,WACJ,aAAa,CAAC,gBAAgB,KAAK,SAAS,IAAI,IAC5C,GAAG,SAAS,KAAK,YACjB,SAAS;KACf,SACE,OAAO,SAAS,eAAe,kBAAkB,OAC7C,SACA,IAAI,KAAK,CAAC,MAAM,GAAG,UAAU,EAAE,MAAM,OAAO,KAAK,CAAC;KACxD,KAAK,kBAAkB,IAAI,QAAQ,SAAS;IAC9C;GACF,SAAS,KAAK;IACZ,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;IAChE,KAAK,MAAM,SAAS,EAAE,MAAM,CAAC;IAC7B,MAAM;GACR;EACF;EAOA,IAAI,SAAS,WAAW,eAAe,gCAAgC,QAAQ,OAAO,GAAG;GACvF,MAAM,wBAAQ,IAAI,MAChB,mKAGF;GACA,KAAK,MAAM,SAAS,EAAE,MAAM,CAAC;GAC7B,MAAM;EACR;EAQA,IAAI;EACJ,IACE,SAAS,WAAW,aACpB,CAAC,QAAQ,UACT,QAAQ,eAAe,WACvB,OAAO,WAAW,YAClB,CAAC,OAAO,WAAW,OAAO,GAC1B;GACA,MAAM,UAAU,MAAM,mBAAmB,MAAM;GAC/C,IAAI,SAAS;IACX,SAAS,SAAS;IAClB,oBAAoB;GACtB;EACF;EAKA,IAAI,EADkB,SAAS,WAAW,aAAa,QAAQ,eAAe,YAC3D,OAAO,WAAW,UACnC,IAAI;GACF,MAAM,0BAA0B,MAAM;EACxC,SAAS,KAAK;GACZ,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAChE,KAAK,MAAM,SAAS,EAAE,MAAM,CAAC;GAC7B,MAAM;EACR;EAKF,MAAM,WAAW,MAAM,KAAK,mBAAmB,QAAQ,SAAS,UAAU,EAAE;EAC5E,IAAI,UAAU,OAAO;EAErB,MAAM,OAAO,QAAQ,QAAQ,SAAS;EACtC,MAAM,QAA0B;GAAE,GAAG;GAAe,GAAG,QAAQ;EAAM;EACrE,MAAM,UAAU,QAAQ,WAAW;EAEnC,MAAM,SAAsB;GAC1B,MAAM;IACJ;IACA;IACA,QAAQ,YACJ;KAAE,MAAM;KAAO,KAAK;IAAU,IAC9B,eAAe,QAAQ,QAAQ,UAAU;IAC7C,QAAQ,SAAS;IACjB,YAAY;IACZ,cAAc;IACd;IACA,SAAS,aAAa,QAAQ,WAAW,CAAC;IAC1C,QAAQ,QAAQ,UAAU,KAAK,SAAS,gBAAgB;IACxD,YAAY,QAAQ,cAAc,KAAK,SAAS,qBAAqB;IACrE,aAAa,QAAQ;IACrB,WAAW,QAAQ,WAAW,KAAK,KAAK,KAAA;IACxC,UAAU,QAAQ,YAAY,KAAK,SAAS;IAC5C;IACA,UAAU,YAAY,EAAE;IACxB,UAAU,CAAC;GACb;GACA;GACA;GACA,aAAa,QAAQ;GACrB,UAAU,OAAO,SAAS,eAAe,kBAAkB,OAAO,OAAO,OAAO,KAAA;GAChF,gBAAgB,QAAQ;EAC1B;EAEA,KAAK,MAAM,WAAW,EAAE,SAAS,WAAW,KAAK,KAAK,CAAC;EAEvD,IAAI;GACF,IAAI,SAAS,WAAW,aAAa,QAAQ,eAAe,SAC1D,MAAM,KAAK,YAAY,QAAQ,SAAS,iBAAiB;QAEzD,MAAM,KAAK,cAAc,QAAQ,OAAO;EAE5C,SAAS,KAAK;GACZ,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAChE,KAAK,MAAM,SAAS,EAAE,MAAM,CAAC;GAC7B,MAAM;EACR;EAEA,KAAK,SAAS,IAAI,IAAI,MAAM;EAC5B,KAAK,QAAQ,aAAa,SAAS,OAAO,KAAK,MAC7C,KAAK,WAAW,OAAO,KAAK,IAAI;EAElC,KAAK,MAAM,cAAc,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;EACtD,OAAO,EAAE,GAAG,OAAO,KAAK;CAC1B;;;;;;CAOA,YAAY,IAAkB;EAC5B,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ;EAEb,KAAK,cAAc,MAAM;EACzB,sBAAsB,KAAK,MAAM,OAAO,KAAK,UAAU,OAAO,KAAK,QAAQ;EAC3E,IAAI,OAAO,aAAa,uBAAuB,OAAO,WAAW;EACjE,IAAI,OAAO,WAAW;GACpB,MAAM,YAAY,OAAO;GACzB,KAAK,WAAW,EACb,MAAM,WAAW,OAAO,UAAU,SAAS,CAAC,EAC5C,YAAY,CAEb,CAAC;EACL;EACA,KAAK,SAAS,OAAO,EAAE;EACvB,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;CAC1D;;;;CAKA,YAAkB;EAChB,KAAK,MAAM,MAAM,MAAM,KAAK,KAAK,SAAS,KAAK,CAAC,GAC9C,KAAK,YAAY,EAAE;CAEvB;;;;;;;CAQA,mBAAmB,IAAY,SAAwB;EACrD,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ;EAKb,oBAAoB,KAAK,MAAM,OAAO,KAAK,UAAU,OAAO;EAC5D,MAAM,UAAU,OAAO,KAAK,YAAY;EACxC,OAAO,KAAK,UAAU;EACtB,IAAI,SAAS,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;CACvE;;;;;;CAOA,YAAY,IAAkB;EAC5B,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ,KAAK,MAAM;EACxB,KAAK,WAAW,OAAO,KAAK,IAAI;CAClC;;;;;;;CAQA,cAAc,IAAY,OAAwC;EAChE,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ;EACb,MAAM,OAAO,OAAO,KAAK;EACzB,MAAM,OAAO;GAAE,GAAG;GAAM,GAAG;EAAM;EACjC,OAAO,KAAK,QAAQ;EAMpB,IAAI,KAAK,yBAAyB,QAAQ,MAAM,IAAI,GAAG;GAUrD,KAAU,oBAAoB,MAAM,EAAE,cAAc;IAClD,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;GAC1D,CAAC;GACD;EACF;EACA,IAAI,KAAK,mBAAmB,QAAQ,MAAM,IAAI,GAK5C,KAAK,uBAAuB,MAAM;OAC7B;GACL,WAAW,KAAK,MAAM,OAAO,MAAM,OAAO,OAAO,KAAK,OAAO;GAC7D,KAAK,kBAAkB,QAAQ,MAAM,MAAM,KAAK;EAClD;EACA,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;CAC1D;;;;;;;CAQA,kBACE,QACA,MACA,MACA,OACM;EACN,MAAM,MAAM,UAAU,IAAI;EAC1B,MAAM,MAAM,UAAU,IAAI;EAC1B,MAAM,UAAU,WAAW,OAAO,KAAK,IAAI,OAAO;EAElD,IAAI,QAAQ,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,OAAO,IAAI;GACjD,KAAK,eAAe,MAAM;GAG1B,KAAK,eAAe,MAAM;GAC1B;EACF;EACA,IAAI,CAAC,KAAK;GACR,IAAI,OAAO,KAAK,KAAK,SAAS,OAAO,GAAG;IACtC,KAAK,KAAK,YAAY,OAAO;IAC7B,OAAO,KAAK,WAAW,OAAO,KAAK,SAAS,QAAQ,OAAO,OAAO,OAAO;IAEzE,KAAK,eAAe,MAAM;GAC5B;GACA;EACF;EAIA,IAAI,MAAM,eAAe,KAAA,GACvB,KAAK,KAAK,kBAAkB,SAAS,cAAc,eAAe,IAAI,CAAC;EAEzE,IAAI,MAAM,cAAc,KAAA,GACtB,KAAK,KAAK,kBAAkB,SAAS,aAAa,KAAK,aAAA,EAA+B;EAExF,IAAI,MAAM,mBAAmB,KAAA,GAC3B,KAAK,KAAK,kBACR,SACA,oBACA,KAAK,mBAAmB,SAAS,SAAS,OAC5C;EAEF,IAAI,MAAM,sBAAsB,KAAA,GAAW;GACzC,MAAM,QAAQ,KAAK,qBAAqB;GACxC,KAAK,KAAK,kBAAkB,SAAS,sBAAsB,KAAK;GAChE,KAAK,KAAK,kBAAkB,SAAS,yBAAyB,KAAK;EACrE;CACF;;;;;CAMA,eAAuB,QAA2B;EAChD,MAAM,UAAU,WAAW,OAAO,KAAK,IAAI,OAAO;EAClD,IAAI,KAAK,KAAK,SAAS,OAAO,GAAG;EACjC,cAAc,KAAK,MAAM;GACvB,SAAS,OAAO,KAAK;GACrB,OAAO,OAAO,KAAK;GACnB,SAAS,OAAO,KAAK;GACrB,SAAS,OAAO,KAAK;GACrB,aAAa,OAAO,KAAK,eAAe,UAAU,OAAO,KAAK,KAAK,KAAA;GACnE,UAAU,OAAO,KAAK;EACxB,CAAC;EACD,IAAI,CAAC,OAAO,KAAK,SAAS,SAAS,OAAO,GAAG,OAAO,KAAK,SAAS,KAAK,OAAO;CAChF;;;;;CAMA,eAAuB,QAA2B;EAChD,IAAI,CAAC,OAAO,KAAK,QAAQ;EACzB,KAAK,cAAc,MAAM;EACzB,KAAK,cAAc,MAAM;CAC3B;;;;;;CAOA,yBACE,QACA,MACA,MACS;EACT,IAAI,OAAO,KAAK,eAAe,aAAa,OAAO,KAAK,iBAAiB,SACvE,OAAO;EAET,IAAI,YAAY,IAAI,MAAM,YAAY,IAAI,GAAG,OAAO;EACpD,OACE,YAAY,IAAI,MAAM,eACpB,KAAK,iBAAiB,SAAS,KAAK,iBAAiB,QACpD,KAAK,kBAAkB,SAAS,KAAK,kBAAkB;CAE9D;;;;;;;;CASA,mBACE,QACA,MACA,MACS;EACT,MAAM,WAAW,OAAO,KAAK;EAC7B,IAAI,aAAa,aAAa,aAAa,WAAW,aAAa,WACjE,OAAO;EAET,OAAQ,KAAK,qBAAqB,UAAW,KAAK,qBAAqB;CACzE;;;;;;CAOA,uBAA+B,QAA2B;EACxD,KAAK,cAAc,MAAM;EACzB,KAAK,MAAM,MAAM,OAAO,KAAK,UAC3B,IAAI,KAAK,KAAK,SAAS,EAAE,GAAG,KAAK,KAAK,YAAY,EAAE;EAEtD,OAAO,KAAK,WAAW,kBAAkB,KAAK,MAAM;GAClD,SAAS,OAAO,KAAK;GACrB,cAAc,OAAO,KAAK;GAC1B,OAAO,OAAO,KAAK;GACnB,SAAS,OAAO,KAAK;GACrB,SAAS,OAAO,KAAK;GACrB,aAAa,OAAO,KAAK,eAAe,UAAU,OAAO,KAAK,KAAK,KAAA;GACnE,UAAU,OAAO,KAAK;EACxB,CAAC;EACD,KAAK,cAAc,MAAM;CAC3B;;;;;;CAOA,MAAc,oBAAoB,QAAoC;EAGpE,MAAM,aAAa,OAAO;EAC1B,IAAI,CAAC,YAAY;EACjB,MAAM,WAAW,OAAO,KAAK;EAC7B,KAAK,cAAc,MAAM;EACzB,sBAAsB,KAAK,MAAM,OAAO,KAAK,UAAU,QAAQ;EAC/D,iBACE,KAAK,MACL,OAAO,KAAK,IACZ,YACA,KAAK,SAAS,aACd,kBAAkB,OAAO,KAAK,cAAc,OAAO,KAAK,KAAK,CAC/D;EACA,MAAM,eAAe,MAAM,gBAAgB,KAAK,MAAM,UAAU;EAChE,OAAO,KAAK,WAAW,kBAAkB,KAAK,MAAM;GAClD,SAAS,OAAO,KAAK;GACrB,cAAc,OAAO,KAAK;GAC1B,OAAO,OAAO,KAAK;GACnB,SAAS,OAAO,KAAK;GACrB,SAAS,OAAO,KAAK;GACrB,UAAU,OAAO,KAAK;GACtB;EACF,CAAC;EACD,KAAK,cAAc,MAAM;CAC3B;;;;;;;;CASA,gBAAgB,IAAY,SAAuB;EACjD,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ;EACb,MAAM,UAAU,aAAa,OAAO;EACpC,IAAI,OAAO,KAAK,YAAY,SAAS;EACrC,OAAO,KAAK,UAAU;EACtB,aAAa,KAAK,MAAM,OAAO,MAAM,OAAO,KAAK,OAAO,OAAO;EAC/D,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;CAC1D;;;;;;;CAQA,eAAe,IAAY,SAAwB;EACjD,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,UAAU,OAAO,KAAK,WAAW,SAAS;EAC/C,OAAO,KAAK,SAAS;EACrB,KAAK,cAAc,MAAM;EACzB,IAAI,SAAS,KAAK,cAAc,MAAM;EACtC,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;CAC1D;;;;;;;;CASA,iBAAiB,IAAY,UAAyB;EACpD,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ;EACb,MAAM,SAAS,YAAY,KAAK,KAAK,SAAS,QAAQ,IAAI,WAAW,KAAA;EAErE,KAAK,MAAM,WAAW,OAAO,KAAK,UAChC,KAAK,KAAK,UAAU,SAAS,MAAM;EAErC,OAAO,KAAK,WAAW;EACvB,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;CAC1D;;;;;;;CAQA,MAAM,cAAc,IAAY,MAAiC;EAC/D,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ;EAEb,MAAM,SAAS,iBAAiB;GAC9B,WAAW;GACX,aAAa,KAAK,SAAS;GAC3B,cAAc,OAAO,KAAK;GAC1B,UAAU,OAAO,KAAK;GACtB,WAAW,KAAK,SAAS;EAC3B,CAAC;EACD,IAAI,WAAW,OAAO,KAAK,YAAY;EAEvC,KAAK,MAAM,WAAW,EAAE,SAAS,aAAa,OAAO,KAAK,KAAK,MAAM,OAAO,KAAK,CAAC;EAElF,IAAI;GACF,KAAK,cAAc,MAAM;GACzB,sBAAsB,KAAK,MAAM,OAAO,KAAK,UAAU,OAAO,KAAK,QAAQ;GAC3E,IAAI,OAAO,aAAa,uBAAuB,OAAO,WAAW;GACjE,OAAO,KAAK,WAAW,CAAC;GAExB,IAAI,WAAW,SACb,MAAM,KAAK,cAAc,MAAM;QAE/B,MAAM,KAAK,gBAAgB,MAAM;EAErC,SAAS,KAAK;GACZ,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAChE,KAAK,MAAM,SAAS,EAAE,MAAM,CAAC;GAC7B,MAAM;EACR;EAEA,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;CAC1D;;;;;;;;;;CAWA,MAAM,YAAY,IAAkD;EAClE,MAAM,SAAS,KAAK,SAAS,IAAI,EAAE;EACnC,IAAI,CAAC,QAAQ,OAAO,KAAA;EAEpB,IAAI,OAAO,OAAO,WAAW,YAAY,CAAC,OAAO,WAAW,OAAO,EAAE,GAAG,OAAO,KAAK;EAEpF,KAAK,MAAM,WAAW,EAAE,SAAS,cAAc,OAAO,KAAK,KAAK,KAAK,CAAC;EAEtE,IAAI;GACF,IAAI,OAAO,aAAa,KAAK,SAAS,WAAW;IAC/C,MAAM,SAAS,MAAM,KAAK,SAAS,UAAU,OAAO,SAAS;IAC7D,IAAI,QAAQ;KACV,OAAO,SACL,OAAO,SAAS,eAAe,kBAAkB,OAC7C,SACA,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,iBAAiB,MAAM,GAAG,EAAE,MAAM,OAAO,KAAK,CAAC;KAC7E,KAAK,kBAAkB,IAAI,OAAO,QAAkB,OAAO,SAAS;IACtE,OAAO;KACL,OAAO,SAAS,OAAO;KACvB,OAAO,YAAY,KAAA;IACrB;GACF;GAEA,KAAK,cAAc,MAAM;GACzB,sBAAsB,KAAK,MAAM,OAAO,KAAK,UAAU,OAAO,KAAK,QAAQ;GAC3E,IAAI,OAAO,aAAa;IACtB,uBAAuB,OAAO,WAAW;IACzC,OAAO,cAAc,KAAA;GACvB;GACA,OAAO,KAAK,WAAW,CAAC;GAGxB,IAAI,OAAO,WAAW;IACpB,MAAM,YAAY,OAAO;IACzB,OAAO,YAAY,KAAA;IAEnB,OAAM,MADe,KAAK,WAAW,GACxB,UAAU,SAAS,EAAE,YAAY,CAE9C,CAAC;GACH;GAIA,MAAM,gBAAoC;IACxC,YAAY,OAAO,KAAK;IACxB,YAAY,OAAO,KAAK;IACxB,aAAa,OAAO;IACpB,WAAW,OAAO,KAAK;GACzB;GACA,IAAI,OAAO,KAAK,WAAW,aAAa,OAAO,KAAK,eAAe,SACjE,MAAM,KAAK,YAAY,QAAQ,aAAa;QAE5C,MAAM,KAAK,cAAc,QAAQ,aAAa;EAElD,SAAS,KAAK;GACZ,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAChE,KAAK,MAAM,SAAS,EAAE,MAAM,CAAC;GAC7B,MAAM;EACR;EAEA,KAAK,MAAM,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;EACxD,OAAO,EAAE,GAAG,OAAO,KAAK;CAC1B;;;;;CAMA,UAAgB;EACd,KAAK,MAAM,UAAU,KAAK,SAAS,OAAO,GAAG;GAC3C,KAAK,cAAc,MAAM;GACzB,sBAAsB,KAAK,MAAM,OAAO,KAAK,UAAU,OAAO,KAAK,QAAQ;GAC3E,IAAI,OAAO,aAAa,uBAAuB,OAAO,WAAW;EACnE;EACA,KAAK,SAAS,MAAM;EAGpB,KAAK,MAAM,UAAU,KAAK,cAAc,OAAO,MAAM;EACrD,KAAK,aAAa,MAAM;EACxB,KAAK,QAAQ,OAAO;EACpB,KAAK,SAAS,KAAA;EACd,IAAI,KAAK,kBAAkB;GACzB,aAAa,KAAK,gBAAgB;GAClC,KAAK,mBAAmB,KAAA;EAC1B;CACF;;;;;;;;;;;;;;;;CAiBA,MAAc,mBACZ,QACA,SACA,UACA,IACiC;EAIjC,IAAI,QAAQ,eAAe;GADC;GAAW;GAAc;EAC1B,EAAmB,SAAS,SAAS,MAAM,GAAG,OAAO;EAEhF,MAAM,SAAS,MAAM,KAAK,WAAW;EACrC,MAAM,eAAe,MAAM,KAAK,cAAc,MAAM;EACpD,MAAM,aAAa,MAAM,OAAO,WAAW,cAAc,aAAa,EAAE,GAAG;GACzE,QAAQ,SAAS;GACjB,UACE,OAAO,SAAS,eAAe,kBAAkB,OAAO,OAAO,OAAO,KAAA;GAIxE,gBAAgB,QAAQ;EAC1B,CAAC;EACD,IAAI,WAAW,UAAU,GAAG,OAAO;EAEnC,MAAM,aAAa,QAAQ,QAAQ,SAAS;EAC5C,MAAM,WAAW,MAAM,KAAK,uBAAuB,YAAY,SAAS,UAAU,UAAU;EAE5F,KAAK,MAAM,WAAW,EACpB,SACE,SAAS,WAAW,IAChB,wBAAwB,WAAW,OACnC,WAAW,SAAS,OAAO,eAAe,WAAW,KAC7D,CAAC;EAED,MAAM,QAA2B,CAAC;EAGlC,MAAM,eAAmC,EAAE,GAAG,QAAQ;EACtD,OAAO,aAAa;EACpB,KAAK,MAAM,aAAa,UAAU;GAChC,MAAM,QAAQ,GAAG,GAAG,GAAG,UAAU,QAAQ,mBAAmB,GAAG;GAC/D,MAAM,KACJ,MAAM,KAAK,QAAQ,QAAQ;IACzB,GAAG;IACH,IAAI;IACJ,MAAM;IACN,aAAa;IACb,WAAW;GACb,CAAC,CACH;EACF;EAGA,IAAI,QAAQ,aAAa,MAAM;GAC7B,MAAM,QAAQ,MAAM,KAAK,SAAS,KAAK,IAAI,EAAE,OAAO,OAAO;GAG3D,IAAI,MAAM,SAAS,GACjB,KAAK,WAAW;IACd,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,EAAE,CAAC;IAClC,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,EAAE,CAAC;IAClC,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,EAAE,CAAC;IAClC,KAAK,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,EAAE,CAAC;GACpC,CAAC;EAEL;EAEA,OAAO,MAAM;CACf;;;;;;;;;;;;;CAcA,MAAc,uBACZ,YACA,SACA,UACA,YACmB;EACnB,MAAM,oBAAoB,UAAuC;GAC/D,MAAM,SAAS,IAAI,IAAI,MAAM,KAAK,SAAS,KAAK,YAAY,CAAC,CAAC;GAC9D,OAAO,WAAW,QAAQ,SAAS,OAAO,IAAI,KAAK,YAAY,CAAC,CAAC;EACnE;EAEA,IAAI,QAAQ,cAAc;GACxB,MAAM,YAAY,iBAAiB,QAAQ,YAAY;GACvD,IAAI,UAAU,WAAW,GACvB,MAAM,IAAI,MACR,iCAAiC,QAAQ,aAAa,KAAK,IAAI,EAAE,aAC5D,WAAW,sBAAsB,WAAW,KAAK,IAAI,EAAE,EAC9D;GAEF,OAAO;EACT;EAEA,MAAM,WAAW,KAAK,eAAe;EACrC,IAAI,CAAC,UAAU,OAAO;EAEtB,MAAM,SAAS,MAAM,SAAS,YAAY;GAAE;GAAY,QAAQ,SAAS;EAAO,CAAC;EAGjF,IAAI,UAAU,MAAM,OAAO;EAC3B,MAAM,WAAW,iBAAiB,MAAM;EACxC,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,eAAA,mCACR,gCAAgC,WAAW,EAC7C;EAEF,OAAO;CACT;;;;;;CAOA,iBAAqD;EACnD,MAAM,aAAa,KAAK,SAAS;EACjC,IAAI,eAAe,OAAO,OAAO;EACjC,IAAI,YAAY,OAAO;EACvB,QAAQ,QAAQ,YAAY;GAC1B,MAAM,YAAY,KAAK,KAAK,eAAe;GAG3C,IAAI,CAAC,WAAW,OAAO;GACvB,MAAM,SAAS,gBAAgB;IAAE;IAAW;IAAQ,YAAY,QAAQ;GAAW,CAAC;GACpF,KAAK,aAAa,IAAI,MAAM;GAC5B,OAAO,OAAO,UAAU,cAAc,KAAK,aAAa,OAAO,MAAM,CAAC;EACxE;CACF;;;;;;;;;CAUA,MAAc,YACZ,QACA,SACA,YACe;EACf,MAAM,WAAW,cAAe,MAAM,KAAK,gBAAgB,OAAO,MAAM;EACxE,MAAM,EAAE,aAAa;EACrB,IAAI,aAAa,SAAS;EAC1B,MAAM,UAAU,2BAA2B,UAAU;EAErD,OAAO,KAAK,eAAe,QAAQ;EACnC,OAAO,KAAK,WAAW;EACvB,OAAO,KAAK,OAAO,QAAQ;EAC3B,OAAO,KAAK,eAAe,QAAQ;EACnC,OAAO,KAAK,SAAS,kBAAkB,UAAU;EAUjD,IARa,iBAAiB;GAC5B,WAAW,QAAQ;GACnB,aAAa,KAAK,SAAS;GAC3B,cAAc,QAAQ;GACtB;GACA,WAAW,KAAK,SAAS;EAC3B,CAEI,MAAS,SAAS;GAKpB,MAAM,KAAK,cAAc,MAAM;GAC/B;EACF;EAQA,MAAM,YAAY,eAAe,UAAU;EAC3C,IAAI,WAAW;GACb,KAAK,MAAM,WAAW,EAAE,SAAS,gBAAgB,OAAO,KAAK,KAAK,cAAc,CAAC;GAEjF,aAAa,OAAM,MADE,KAAK,WAAW,GACX,iBAAiB,YAAY,SAAS;GAChE,MAAM,qBAAqB,2BAA2B,UAAU;GAGhE,OAAO,KAAK,OAAO,mBAAmB;EACxC;EAEA,OAAO,KAAK,aAAa;EAGzB,OAAO,UAAU,QAAQ,iBAAiB,UAAU,aAAa,KAAA;EACjE,iBACE,KAAK,MACL,OAAO,KAAK,IACZ,YACA,KAAK,SAAS,aACd,kBAAkB,QAAQ,cAAc,OAAO,KAAK,KAAK,CAC3D;EACA,MAAM,eAAe,MAAM,gBAAgB,KAAK,MAAM,UAAU;EAChE,OAAO,KAAK,WAAW,kBAAkB,KAAK,MAAM;GAClD,SAAS,OAAO,KAAK;GACrB,cAAc,QAAQ;GACtB,OAAO,OAAO,KAAK;GACnB,SAAS,OAAO,KAAK;GACrB,SAAS,OAAO,KAAK;GACrB,UAAU,OAAO,KAAK;GACtB;EACF,CAAC;EACD,KAAK,cAAc,MAAM;CAC3B;;;;;CAMA,MAAc,cAAc,QAAqB,SAA4C;EAC3F,MAAM,UAAU,MAAM,KAAK,QAAQ,MAAM;EAEzC,OAAO,KAAK,eAAe,QAAQ;EACnC,OAAO,KAAK,WAAW,QAAQ,YAAY,OAAO,KAAK;EACvD,OAAO,KAAK,OAAO,QAAQ;EAC3B,OAAO,KAAK,eAAe,QAAQ;EAUnC,IARa,iBAAiB;GAC5B,WAAW,QAAQ;GACnB,aAAa,KAAK,SAAS;GAC3B,cAAc,QAAQ;GACtB,UAAU,OAAO,KAAK;GACtB,WAAW,KAAK,SAAS;EAC3B,CAEI,MAAS,SACX,MAAM,KAAK,cAAc,MAAM;OAE/B,MAAM,KAAK,gBAAgB,MAAM;CAErC;;;;;CAMA,MAAc,QAAQ,QAAqB;EACzC,MAAM,SAAS,MAAM,KAAK,WAAW;EACrC,MAAM,YAAY,aAAa,OAAO,KAAK,EAAE;EAC7C,MAAM,SAAS,MAAM,KAAK,cAAc,OAAO,MAAM;EACrD,KAAK,MAAM,WAAW,EACpB,SACE,OAAO,KAAK,eAAe,WACvB,WAAW,OAAO,KAAK,KAAK,qCAC5B,WAAW,OAAO,KAAK,KAAK,iBACpC,CAAC;EACD,MAAM,UAAU,MAAM,OAAO,OAAO,QAAQ,WAAW;GACrD,QAAQ,OAAO,KAAK;GACpB,aAAa,OAAO;GACpB,WAAW,OAAO,KAAK;GACvB,UAAU,OAAO,YAAY,KAAK,iBAAiB,MAAM;GACzD,MAAM,OAAO,KAAK;GAClB,gBAAgB,OAAO;EACzB,CAAC;EACD,OAAO,YAAY,QAAQ;EAC3B,OAAO,KAAK,SAAS,QAAQ;EAG7B,OAAO,KAAK,aAAa,QAAQ,WAAW,WAAW;EACvD,OAAO;CACT;;;;;CAMA,MAAc,cAAc,QAAoC;EAC9D,MAAM,SAAS,MAAM,KAAK,WAAW;EACrC,IAAI,CAAC,OAAO,WAAW;GACrB,MAAM,UAAU,MAAM,KAAK,QAAQ,MAAM;GACzC,OAAO,KAAK,eAAe,QAAQ;GACnC,OAAO,KAAK,OAAO,QAAQ,QAAQ,OAAO,KAAK;GAC/C,OAAO,KAAK,eACV,QAAQ,iBAAiB,YAAY,QAAQ,eAAe,OAAO,KAAK;EAC5E;EACA,MAAM,YAAY,OAAO;EACzB,IAAI,OAAO,KAAK,eAAe,UAC7B,KAAK,MAAM,WAAW,EACpB,SAAS,YAAY,OAAO,KAAK,KAAK,uCACxC,CAAC;EAEH,MAAM,OAAO,aAAa,SAAS;EAEnC,MAAM,KAAK,OAAO,KAAK;EAGvB,MAAM,cAAc,OAAO,eAAe,WAAW,GAAG,GAAG,OAAO;EAClE,OAAO,cAAc;EACrB,MAAM,qBAAqB,cAAc,GAAG,GAAG,GAAG,WAChD,KAAK,mBAAmB,OAAO,QAAQ,WAAW,IAAI,GAAG,GAAG,GAAG,MAAM,CAAC,CACxE;EAEA,OAAO,KAAK,aAAa;EAGzB,OAAO,UAAU,KAAA;EACjB,oBAAoB,KAAK,MAAM,IAAI;GACjC,SAAS,WAAW,WAAW;GAC/B,SAAS,KAAK,SAAS,eAAe;GACtC,QAAQ,OAAO,KAAK;GACpB,aAAa,KAAK,SAAS;EAC7B,CAAC;EACD,OAAO,KAAK,WAAW,kBAAkB,KAAK,MAAM;GAClD,SAAS;GACT,cAAc,OAAO,KAAK;GAC1B,OAAO,OAAO,KAAK;GACnB,SAAS,OAAO,KAAK;GACrB,SAAS,OAAO,KAAK;GACrB,aAAa;GACb,UAAU,OAAO,KAAK;EACxB,CAAC;EACD,KAAK,cAAc,MAAM;CAC3B;;;;;CAMA,MAAc,gBAAgB,QAAoC;EAChE,IAAI;EACJ,IAAI,OAAO,WAAW;GACpB,MAAM,SAAS,MAAM,KAAK,WAAW;GACrC,KAAK,MAAM,WAAW,EAAE,SAAS,cAAc,OAAO,KAAK,KAAK,gBAAgB,CAAC;GACjF,aAAa,MAAM,OAAO,cAAc,OAAO,SAAS;GACxD,aAAa,MAAM,kBACjB,OAAO,QACP,YACA,OAAO,aACJ,OAAO,KAAK,OAAO,SAAS,SAAS,OAAO,KAAK,OAAO,WAAW,KAAA,EACxE;EACF,OACE,cAAc,MAAM,KAAK,gBAAgB,OAAO,MAAM,GAAG;EAG3D,IAAI,OAAO,KAAK,iBAAiB,WAC/B,OAAO,KAAK,eAAe,2BAA2B,UAAU,EAAE;EAEpE,OAAO,KAAK,SAAS,kBAAkB,UAAU;EAEjD,OAAO,KAAK,aAAa;EAEzB,OAAO,UAAU,OAAO,KAAK,iBAAiB,UAAU,aAAa,KAAA;EACrE,iBACE,KAAK,MACL,OAAO,KAAK,IACZ,YACA,KAAK,SAAS,aACd,kBAAkB,OAAO,KAAK,cAAc,OAAO,KAAK,KAAK,CAC/D;EACA,MAAM,eAAe,MAAM,gBAAgB,KAAK,MAAM,UAAU;EAChE,OAAO,KAAK,WAAW,kBAAkB,KAAK,MAAM;GAClD,SAAS,OAAO,KAAK;GACrB,cAAc,OAAO,KAAK;GAC1B,OAAO,OAAO,KAAK;GACnB,SAAS,OAAO,KAAK;GACrB,SAAS,OAAO,KAAK;GACrB,UAAU,OAAO,KAAK;GACtB;EACF,CAAC;EACD,KAAK,cAAc,MAAM;CAC3B;;;;CAKA,MAAc,gBACZ,QAC+D;EAC/D,IAAI,OAAO,WAAW,UAAU;GAC9B,MAAM,WAAW,MAAM,MAAM,MAAM;GACnC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,mBAAmB,OAAO,IAAI,SAAS,OAAO,GAAG,SAAS,YAAY;GAExF,MAAM,OAAO,MAAM,SAAS,KAAK;GACjC,OAAO;IAAE,YAAY,oBAAoB,KAAK,MAAM,IAAI,CAAC;IAAG,UAAU,KAAK;GAAO;EACpF;EAEA,IAAI,OAAO,SAAS,eAAe,kBAAkB,MAAM;GACzD,MAAM,OAAO,MAAM,OAAO,KAAK;GAC/B,OAAO;IAAE,YAAY,oBAAoB,KAAK,MAAM,IAAI,CAAC;IAAG,UAAU,OAAO;GAAK;EACpF;EAEA,OAAO,EAAE,YAAY,oBAAoB,MAAkD,EAAE;CAC/F;;;;;;CAOA,MAAc,cAAc,QAAyD;EACnF,IAAI,OAAO,WAAW,UAAU;GAC9B,IAAI,OAAO,WAAW,OAAO,GAC3B,QAAQ,MAAM,MAAM,MAAM,GAAG,KAAK;GAEpC,OAAO;EACT;EACA,IAAI,OAAO,SAAS,eAAe,kBAAkB,MAAM,OAAO;EAClE,OAAO,IAAI,KAAK,CAAC,KAAK,UAAU,MAAM,CAAC,GAAG,EAAE,MAAM,uBAAuB,CAAC;CAC5E;;;;;CAMA,iBAAyB,QAA6B;EACpD,MAAM,aAAqC;GACzC,SAAS;GACT,YAAY;GACZ,YAAY;GACZ,WAAW;GACX,YAAY;GACZ,KAAK;EACP;EACA,MAAM,SAAS,OAAO,KAAK;EAC3B,MAAM,MAAM,WAAW,YAAY,WAAW,YAAY,SAAS;EACnE,OAAO,GAAG,aAAa,OAAO,KAAK,EAAE,EAAE,GAAG;CAC5C;;;;;CAMA,cAAsB,QAA2B;EAC/C,IAAI,CAAC,OAAO,KAAK,QAAQ;EACzB,OAAO,iBAAiB,OAAO,KAAK,SAAS,KAAK,YAAY;GAC5D,MAAM,SAAS,MAA0B;IACvC,MAAM,UAAU,EAAE,WAAW;IAC7B,IAAI,SACF,KAAU,WAAW,OAAO,MAAM,EAAE,QAAQ,QAAQ,cAAc,CAAC,CAAC;GAExE;GACA,MAAM,cAAc;IAClB,KAAK,KAAK,UAAU,EAAE,MAAM,SAAS;GACvC;GACA,MAAM,cAAc;IAClB,KAAK,KAAK,UAAU,EAAE,MAAM,SAAS;GACvC;GACA,KAAK,KAAK,GAAG,SAAS,SAAS,KAAK;GACpC,KAAK,KAAK,GAAG,cAAc,SAAS,KAAK;GACzC,KAAK,KAAK,GAAG,cAAc,SAAS,KAAK;GACzC,OAAO;IAAE;IAAS;IAAO;IAAO;GAAM;EACxC,CAAC;CACH;;;;CAKA,cAAsB,QAA2B;EAC/C,KAAK,MAAM,WAAW,OAAO,kBAAkB,CAAC,GAAG;GACjD,KAAK,KAAK,IAAI,SAAS,QAAQ,SAAS,QAAQ,KAAK;GACrD,KAAK,KAAK,IAAI,cAAc,QAAQ,SAAS,QAAQ,KAAK;GAC1D,KAAK,KAAK,IAAI,cAAc,QAAQ,SAAS,QAAQ,KAAK;EAC5D;EACA,OAAO,iBAAiB,KAAA;EAGxB,IAAI,KAAK,kBAAkB,OAAO,KAAK,IAAI;GACzC,KAAK,QAAQ,OAAO;GACpB,KAAK,SAAS,KAAA;GACd,KAAK,gBAAgB,KAAA;EACvB;CACF;;CAGA,MAAc,WACZ,MACA,QACA,YACe;EACf,MAAM,YAAY,SAAS,cAAc,KAAK;EAC9C,UAAU,YAAY;EAEtB,MAAM,QAAQ,SAAS,cAAc,KAAK;EAC1C,MAAM,YAAY;EAClB,MAAM,cAAc,KAAK;EACzB,UAAU,YAAY,KAAK;EAE3B,MAAM,UAAU,OAAO,QAAQ,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,WAAW,aAAa,CAAC;EAC3F,IAAI,QAAQ,WAAW,GAAG;GACxB,MAAM,QAAQ,SAAS,cAAc,KAAK;GAC1C,MAAM,YAAY;GAClB,MAAM,cAAc;GACpB,UAAU,YAAY,KAAK;EAC7B,OAAO;GACL,MAAM,QAAQ,SAAS,cAAc,OAAO;GAC5C,MAAM,YAAY;GAClB,KAAK,MAAM,CAAC,KAAK,UAAU,SAAS;IAClC,MAAM,MAAM,MAAM,UAAU;IAC5B,MAAM,UAAU,IAAI,WAAW;IAC/B,QAAQ,YAAY;IACpB,QAAQ,cAAc;IACtB,MAAM,YAAY,IAAI,WAAW;IACjC,IACE,IAAI,YAAY,MAAM,iBACtB,OAAO,UAAU,YACjB,UAAU,KAAK,KAAK,GACpB;KACA,MAAM,SAAS,IAAI,UAAU,EAAE,gBAAgB,OAAO,WAAW;KACjE,MAAM,UAAU,IAAI,IAAI;MACtB;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;KACF,CAAC;KACD,MAAM,QAAQ,MAAY,WAAuB;MAC/C,IAAI,KAAK,aAAa,KAAK,WAAW;OACpC,OAAO,YAAY,SAAS,eAAe,KAAK,eAAe,EAAE,CAAC;OAClE;MACF;MACA,IAAI,EAAE,gBAAgB,UAAU;MAChC,MAAM,MAAM,KAAK,UAAU,YAAY;MACvC,IAAI,QAAQ,YAAY,QAAQ,WAAW,QAAQ,UAAU,QAAQ,QAAQ;MAC7E,IAAI,CAAC,QAAQ,IAAI,GAAG,GAAG;OACrB,KAAK,MAAM,aAAa,KAAK,YAAY,KAAK,WAAW,MAAM;OAC/D;MACF;MACA,MAAM,UAAU,SAAS,cAAc,GAAG;MAC1C,IAAI,QAAQ,KAAK;OACf,MAAM,OAAO,KAAK,aAAa,MAAM,GAAG,KAAK;OAC7C,IAAI,QAAQ,sBAAsB,KAAK,IAAI,GAAG;QAC5C,QAAQ,aAAa,QAAQ,IAAI;QACjC,QAAQ,aAAa,UAAU,QAAQ;QACvC,QAAQ,aAAa,OAAO,qBAAqB;OACnD;MACF;MACA,KAAK,MAAM,aAAa,KAAK,YAAY,KAAK,WAAW,OAAO;MAChE,OAAO,YAAY,OAAO;KAC5B;KACA,KAAK,MAAM,aAAa,OAAO,KAAK,YAAY,KAAK,WAAW,SAAS;IAC3E,OACE,UAAU,cAAc,UAAU,QAAQ,UAAU,KAAA,IAAY,KAAK,OAAO,KAAK;GAErF;GACA,UAAU,YAAY,KAAK;EAC7B;EAEA,MAAM,WAAW,MAAM,YAAY;EACnC,KAAK,QAAQ,OAAO;EACpB,MAAM,QAAQ,IAAI,SAAS,MAAM;GAAE,aAAa;GAAM,UAAU;EAAQ,CAAC;EACzE,MAAM,UAAU,CAAC,OAAO,KAAK,OAAO,GAAG,CAAC;EACxC,MAAM,cAAc,SAAS;EAC7B,MAAM,MAAM,KAAK,IAAI;EACrB,KAAK,SAAS;EACd,KAAK,gBAAgB,KAAK;CAC5B;;;;;;;CAQA,mBAA2B,MAAgD;EACzE,KAAK,iBAAiB;EACtB,IAAI,KAAK,kBAAkB;GACzB,aAAa,KAAK,gBAAgB;GAClC,KAAK,mBAAmB,KAAA;EAC1B;EACA,KAAK,MAAM,WAAW,EAAE,SAAS,qBAAqB,KAAK,cAAc,cAAc,CAAC;EAExF,MAAM,eAAe;GACnB,KAAK,iBAAiB;GACtB,IAAI,KAAK,kBAAkB,GACzB,KAAK,mBAAmB,iBAAiB;IACvC,KAAK,mBAAmB,KAAA;IACxB,KAAK,MAAM,WAAW,EAAE,SAAS,GAAG,CAAC;GACvC,GAAG,GAAG;QAEN,KAAK,MAAM,WAAW,EAAE,SAAS,qBAAqB,KAAK,cAAc,cAAc,CAAC;EAE5F;EAEA,OAAO,KAAK,MACT,UAAU;GACT,OAAO;GACP,OAAO;EACT,IACC,QAAQ;GACP,OAAO;GACP,MAAM;EACR,CACF;CACF;CAEA,WAAmB,MAA8C;EAC/D,aAAa,KAAK,MAAM,MAAM;GAAE,SAAS;GAAI,UAAU;GAAK,SAAS;EAAG,CAAC;CAC3E;AACF;;;;;;ACzjDA,IAAa,qBAAqB;;;;;;;AAQlC,SAAgB,WAAW,MAAsB;CAC/C,OAAO,IAAI,KAAK,QAAQ,MAAM,MAAI,EAAE;AACtC;;;;;;;AAQA,SAAgB,aAAa,OAAuB;CAClD,OAAO,IAAI,MAAM,QAAQ,MAAM,IAAI,EAAE;AACvC;;;;;;;;;;;;AAaA,SAAgB,UAAU,QAAsB,MAAc,aAA8B;CAC1F,QAAQ,QAAR;EACE,KAAK,cACH,OAAO,gBAAgB,aAAa,IAAI,EAAE;EAC5C,KAAK,OACH,OAAO,YAAY,aAAa,IAAI,EAAE;EACxC,SAAS;GACP,MAAM,WAAW,cAAc,aAAa,aAAa,WAAW,MAAM;GAC1E,OAAO,WAAW,aAAa,IAAI,IAAI,SAAS;EAClD;CACF;AACF;;;;;;;;;AAUA,SAAgB,SAAS,QAAsB,MAAsB;CACnE,IAAI,WAAW,eAAe,UAAU,KAAK,KAAK,MAAM,MAAM,EAAE,EAAE,GAEhE,OAAO,GADQ,gBAAgB,KAAK,IAAI,IAAI,sBAAsB,aAC/C;CAErB,OAAO;AACT;;;;;;;;AASA,SAAgB,yBAAyB,UAA0B;CACjE,OAAO,0BAA0B;AACnC;AAgBA,IAAM,4BAA4B;CAChC;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,SAAS,YAAY,MAAsB;CACzC,MAAM,OAAO,0BAA0B,QAAQ,KAAK,YAAY,CAAC;CACjE,OAAO,SAAS,KAAK,OAAO,mBAAmB;AACjD;;;;;;;;;;;AAYA,SAAgB,qBACd,SACoC;CACpC,MAAM,SAAS,QAAQ,MAAM,WAAW,OAAO,KAAK,YAAY,EAAE,WAAW,UAAU,CAAC;CACxF,IAAI,QAAQ,OAAO;EAAE,MAAM,OAAO;EAAM,UAAU;CAAW;CAE7D,MAAM,sBAAsB,QACzB,QAAQ,WAAW,YAAY,OAAO,IAAI,MAAM,OAAO,gBAAgB,EACvE,MAAM,GAAG,MAAM,YAAY,EAAE,IAAI,IAAI,YAAY,EAAE,IAAI,CAAC;CAC3D,MAAM,YAAY,oBAAoB,MAAM,WAC1C,4BAA4B,KAAK,OAAO,IAAI,CAC9C;CACA,IAAI,WAAW,OAAO;EAAE,MAAM,UAAU;EAAM,UAAU;CAAM;CAE9D,MAAM,sBAAsB,oBACzB,QAAQ,WAAW,0BAA0B,KAAK,OAAO,IAAI,CAAC,EAC9D,KAAK,WAAW,OAAO,IAAI;CAC9B,IAAI,oBAAoB,SAAS,GAC/B,OAAO;EACL,MAAM,oBAAoB;EAC1B,UAAU;EACV,6BAA6B;EAC7B;CACF;AAGJ;;;;;;;;;;AAWA,SAAgB,eACd,WACA,QACA,gBACQ;CACR,MAAM,SACJ,mBAAmB,SACf,KACA,YAAY,WAAW,cAAc,EAAE;CAC7C,OAAO,2BAA2B,WAAW,SAAS,EAAE,cAAc,OAAO,QAAQ;AACvF;AAEA,SAAS,sBAAsB,UAA0C;CACvE,IAAI,SAAS,6BACX,MAAM,IAAI,MAAM,yEAAyE;CAE3F,MAAM,SAAS,WAAW,SAAS,IAAI;CAEvC,OAAO,kBADK,SAAS,aAAa,eAAe,eAAe,OAAO,KAAK,OAC/C;AAC/B;;;;;;;;;;;AAYA,SAAS,oBAAoB,UAAkB,WAAkC;CAC/E,OAAO,YACH,gBAAgB,SAAS,IAAI,aAAa,SAAS,EAAE,qCACrD;AACN;AAEA,SAAS,8BACP,cACA,WACA,QACA,UACA,YAA2B,MACnB;CAGR,IAAI,SAAS,aAAa,cAAc,CAAC,WACvC,OAAO,iBAAiB,UACpB,eAAe,WAAW,QAAQ,SAAS,IAAI,IAC/C,cAAc,WAAW,QAAQ,SAAS,IAAI;CAEpD,MAAM,UACJ,SAAS,aAAa,aAClB,WAAW,SAAS,IAAI,IACxB,sBAAsB,QAAQ;CACpC,OACE,qBAAqB,aAAa,GAAG,WAAW,SAAS,EAAE,wBACtC,WAAW,SAAS,IAAI,EAAE,KAC5C,oBAAoB,SAAS,SAAS,EAAE,gBACnC;AAEZ;;;;;;;;;;;;AAaA,SAAgB,2BACd,WACA,QACA,UACA,YAA2B,MACnB;CACR,OAAO,8BAA8B,SAAS,WAAW,QAAQ,UAAU,SAAS;AACtF;;;;;;;;;AAUA,SAAgB,sBACd,WACA,QACA,WACA,YAA2B,MACnB;CACR,MAAM,OAAO,oBAAoB,mBAAmB,WAAW,SAAS,EAAE,IAAI,SAAS;CACvF,OACE,2BAA2B,WAAW,SAAS,EAAE,wBAC5B,WAAW,SAAS,EAAE,KACxC,KAAK,gBAAgB;AAE5B;;;;;;;;;;;AAYA,SAAgB,yBACd,WACA,QACA,WACA,WACA,YAA2B,MACnB;CACR,MAAM,OAAO,oBACX,YAAY,WAAW,SAAS,EAAE,IAAI,WAAW,SAAS,EAAE,IAC5D,SACF;CACA,OACE,2BAA2B,WAAW,SAAS,EAAE,gBACpC,KAAK,gBACV;AAEZ;;;;;;;;;;;;AAaA,SAAgB,cACd,WACA,QACA,gBACQ;CACR,MAAM,SACJ,mBAAmB,SAAS,KAAK,YAAY,WAAW,cAAc,EAAE;CAC1E,OAAO,0BAA0B,WAAW,SAAS,EAAE,cAAc,OAAO,QAAQ;AACtF;;;;;;;;;AAUA,SAAgB,0BACd,WACA,QACA,UACA,YAA2B,MACnB;CACR,OAAO,8BAA8B,QAAQ,WAAW,QAAQ,UAAU,SAAS;AACrF;;;;;;;;;;AAWA,SAAgB,qBAAqB,MAAc,MAAuB;CACxE,MAAM,QAAQ,KAAK,YAAY;CAC/B,IAAI,UAAU,UAAU,CAAC,MAAM,SAAS,OAAO,GAAG,OAAO;CACzD,MAAM,QAAQ,KAAK,YAAY;CAC/B,OACE,MAAM,WAAW,QAAQ,KACzB,WAAW,KAAK,KAAK,KACrB,WAAW,KAAK,KAAK,KACrB,WAAW,KAAK,KAAK,KACrB,WAAW,KAAK,KAAK;AAEzB;;;;;;;;;AAUA,SAAgB,iBAAiB,WAAmB,YAA4B;CAC9E,MAAM,QAAQ,WAAW,SAAS;CAClC,MAAM,OAAO,WAAW,UAAU;CAClC,OACE,iDACO,KAAK,8BAA8B,KAAK,8BACxC,KAAK,8BAA8B,KAAK,8BACvC;AAEZ;;;;;;;;;AAUA,SAAgB,0BAA0B,WAAmB,aAAa,KAAa;CACrF,OACE,kGAC0B,WAAW,SAAS,EAAE,gCAAgC,WAAW;AAE/F;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBACd,WACA,WACA,GACA,GACA,GACA,UACA,iBACA,YACQ;CACR,MAAM,QAAQ,WAAW,SAAS;CAClC,MAAM,CAAC,MAAM,OAAO,MAAM,SAAS;CACnC,MAAM,UAAU,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE;CACjD,MAAM,UAAU,mBAAmB,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM;CACrE,MAAM,QAAQ,gBACX,KAAK,MAAM,GAAG,aAAa,CAAC,EAAE,aAAa,WAAW,CAAC,EAAE,aAAa,EACtE,KAAK,IAAI;CAIZ,MAAM,SAAS,gBAAgB,2FADhB,QAAQ,MACmB,QAAQ,KAAK,UAAU,GAAG;CACpE,MAAM,aAAa,aACf,GAAG,WAAW,UAAU,EAAE,WAAW,KAAK,OAAO,WAAW,UAAU,EAAE,WAAW,KAAK,OACjF,WAAW,UAAU,EAAE,WAAW,MAAM,OAAO,WAAW,UAAU,EAAE,WAAW,MAAM,SAC9F;CACJ,OACE,mBAAmB,OAAO,IAAI,aAAa,SAAS,EAAE,gCACrC,MAAM,SACd,WAAW,2CAA2C,QAAQ,UAC9D,mBAAmB;AAEhC;;;;;;;AAQA,SAAgB,aAAa,WAA2B;CAEtD,OACE,yMAFY,WAAW,SAKf,EAAM;AAElB;;;;;;;AAQA,SAAgB,mBAAmB,WAA2B;CAC5D,OACE,gFACQ,WAAW,SAAS,EAAE;AAElC;;;;;;;;AASA,SAAgB,mBAAmB,WAAmB,iBAAmC;CACvF,MAAM,QAAQ,gBAAgB,KAAK,MAAM,WAAW,CAAC,CAAC,EAAE,KAAK,IAAI;CAEjE,OACE,yCAFkB,QAAQ,KAAK,UAAU,GAEY,QAC7C,WAAW,SAAS,EAAE;AAElC;;;;;;;;AASA,SAAgB,oBAAoB,WAAmB,UAA0B;CAC/E,MAAM,SAAS,WAAW,QAAQ;CAClC,OAAO,UAAU,OAAO,mBAAmB,WAAW,SAAS,EAAE,SAAS,OAAO;AACnF;;;;;;;;;AAUA,SAAgB,gBAAgB,WAA2D;CACzF,MAAM,QAAQ,WAAW,SAAS;CAClC,MAAM,YAAY,WAAW,OAAO,UAAU,MAAM;CACpD,OAAO;EACL,WAAW,CACT,eAAe,MAAM,+CACrB,UAAU,MAAM,iFAClB;EACA,OAAO,8BAA8B,UAAU,MAAM,MAAM;CAC7D;AACF;;;;;;;;;;;;;;AAeA,SAAgB,aACd,WACA,WACA,GACA,GACA,GACA,iBACQ;CACR,MAAM,QAAQ,WAAW,SAAS;CAClC,MAAM,MAAM,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE;CAC7C,MAAM,QAAQ,gBACX,KAAK,MAAM,GAAG,aAAa,CAAC,EAAE,aAAa,WAAW,CAAC,EAAE,aAAa,EACtE,KAAK,IAAI;CAEZ,OACE,mBAAmB,kDAF4C,IAAI,IAAI,QAAQ,KAAK,UAAU,GAAG,GAEvE,IAAI,aAAa,SAAS,EAAE,gCACrC,MAAM,4DACqC,IAAI,UACvD,mBAAmB;AAEhC;;;;;;;;;;AAWA,SAAgB,kBACd,WACA,MACA,iBACQ;CACR,MAAM,QAAQ,WAAW,SAAS;CAClC,MAAM,WAAW,mBAAmB,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG;CAChF,MAAM,QAAQ,gBAAgB,KAAK,MAAM,WAAW,CAAC,CAAC,EAAE,KAAK,IAAI;CAEjE,OACE,yCAFkB,QAAQ,KAAK,UAAU,GAEY,QAAQ,MAAM,kDACjB,SAAS,UAClD;AAEb;;;;;;;;AASA,SAAgB,gBAAgB,MAAsB;CACpD,OACE,oFACqD,aAAa,IAAI,EAAE;AAE5E;;;;;;;;;;;AAYA,SAAgB,iBAAiB,MAAc,aAA8B;CAC3E,MAAM,WAAW,cAAc,aAAa,aAAa,WAAW,MAAM;CAC1E,OAAO,WAAW,aAAa,IAAI,IAAI,SAAS;AAClD;;;;;;;;;;AAWA,SAAgB,mBAAmB,MAAsB;CACvD,OACE,0LAIqB,aAAa,IAAI,EAAE;AAE5C;;AASA,IAAa,6BAA6B;;;;;;;;;;;;;;AAe1C,SAAgB,mBAAmB,MAAsB;CACvD,OACE,2BAA2B,2BAA2B,4BAC1B,aAAa,IAAI,EAAE,uBACzB,aAAA,KAAoC,EAAE;AAEhE;;;;;;AAOA,SAAgB,gBAAwB;CACtC,OACE;AAGJ;;;;AAKA,IAAa,mBAAmB;CAAC;CAAY;CAAO;CAAQ;CAAY;AAAc;;;;AAKtF,IAAa,uBAAgD;CAC3D,CAAC,aAAa,UAAU;CACxB,CAAC,OAAO,KAAK;CACb,CAAC,OAAO,KAAK;CACb,CAAC,KAAK,GAAG;AACX;;;;;AC9oBA,IAAa,kBAAkB;;;;;;;;;;;;;;AAe/B,SAAgB,oBAAuB,SAAY,MAAiB;CAClE,MAAM,aAAa,KAAK,QAAQ,QAAQ,EAAE;CAC1C,IAAI,eAAe,iBAAiB,OAAO;CAC3C,MAAM,UAAU,KAAK,UAAU,OAAO,EAAE,MAAM,eAAe,EAAE,KAAK,UAAU;CAC9E,OAAO,KAAK,MAAM,OAAO;AAC3B;;;;;;;;;;;;AAkDA,SAAgB,wBAAwB,sBAAuC;CAC7E,IAAI,CAAC,sBAAsB,OAAO;CAElC,OAAO,SADY,qBAAqB,QAAQ,OAAO,GAAG,EAAE,QAAQ,MAAM,IAC1D,EAAW;AAC7B;;;;;;AAOA,IAAM,gBAAgB,IAAI,SAAS,OAAO,oBAAoB;;;;;;;;;AAY9D,SAAgB,cAAc,KAA+C;CAC3E,OAAO,cAAc,GAAG;AAC1B;AAEA,IAAM,oCAAoB,IAAI,IAA2B;;;;;;;;;AAUzD,SAAgB,kBAAkB,KAA4B;CAC5D,IAAI,UAAU,kBAAkB,IAAI,GAAG;CACvC,IAAI,CAAC,SAAS;EACZ,UAAU,IAAI,SAAe,SAAS,WAAW;GAC/C,MAAM,SAAS,SAAS,cAAc,QAAQ;GAC9C,OAAO,MAAM;GACb,OAAO,QAAQ;GACf,OAAO,eAAe,QAAQ;GAC9B,OAAO,gBAAgB;IACrB,kBAAkB,OAAO,GAAG;IAC5B,uBAAO,IAAI,MAAM,0BAA0B,KAAK,CAAC;GACnD;GACA,SAAS,KAAK,YAAY,MAAM;EAClC,CAAC;EACD,kBAAkB,IAAI,KAAK,OAAO;CACpC;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;AAkBA,eAAsB,WACpB,YACA,SACA,sBACuB;CACvB,aAAa,wBAAwB;CACrC,MAAM,QAAQ,WAAW,iBAAiB,QAAQ,QAAQ,EAAE;CAE5D,MAAM,SAAc,MAAM,cAAc,GAAG,KAAK,MAAM;CAEtD,MAAM,UAAU,oBAAoB,OAAO,mBAAmB,GAAG,IAAI;CACrE,MAAM,SAAS,MAAM,OAAO,aAAa,OAAO;CAEhD,MAAM,YAAY,IAAI,gBACpB,IAAI,KAAK,CAAC,kBAAkB,OAAO,WAAW,IAAI,GAAG,EAAE,MAAM,kBAAkB,CAAC,CAClF;CACA,MAAM,SAAS,IAAI,OAAO,SAAS;CACnC,MAAM,SAAS,IAAI,OAAO,WAAW;CACrC,MAAM,KAAU,IAAI,OAAO,YAAY,QAAQ,MAAM;CACrD,IAAI;EACF,MAAM,GAAG,YAAY,OAAO,YAAY,OAAO,aAAa;CAC9D,UAAU;EACR,IAAI,gBAAgB,SAAS;CAC/B;CAEA,aAAa,8BAA8B;CAC3C,MAAM,OAAyB,MAAM,GAAG,QAAQ;CAChD,MAAM,KAAK,MAAM,wBAAwB,oBAAoB,CAAC;CAE9D,MAAM,eAAe,MAAM,KAAK,MAAM,uBAAuB,GAAG,QAAQ;CACxE,MAAM,UAAU,OAAO,YAAY,IAAI,KAAK,SAAS;CAErD,IAAI,cAAc;CAClB,IAAI;EACF,MAAM,KAAK,MAAM,cAAc,CAAC;EAChC,cAAc;CAChB,QAAQ,CAER;CAEA,MAAM,eAAe,OAAO,OAAO,oBAAoB,QAAQ,CAAC;CAGhE,OAAO;EAAM;EAAsB;EAAM;EAAa;EAAS;CAAa;AAC9E;;AC/KA,IAAa,iBAAiB;AAE9B,IAAM,eAAe;;AAwBrB,SAAgB,gBAAgB,OAA4B;CAC1D,IAAI,MAAM,SAAS,IAAqB,OAAO;CAC/C,KAAK,IAAI,IAAI,GAAG,IAAI,IAAqB,KAAK,GAC5C,IAAI,MAAM,OAAO,aAAa,WAAW,CAAC,GAAG,OAAO;CAEtD,OAAO;AACT;AAEA,SAAgB,gBAAgB,OAAuB;CACrD,OAAO,IAAI,MAAM,QAAQ,MAAM,MAAI,EAAE;AACvC;AAEA,SAAgB,YAAY,IAAmB,MAAuB;CACpE,MAAM,SAAS,GAAG,KAChB,iEACA,EAAE,SAAS,KAAK,CAClB;CACA,OAAO,OAAO,SAAS,KAAK,OAAO,GAAG,OAAO,SAAS;AACxD;;;;;;;;;;;AAYA,SAAgB,2BACd,KACA,OACY;CACZ,MAAM,KAAK,IAAI,IAAI,SAAS,KAAK;CACjC,IAAI;EAEF,IAAI,CAAC,YAAY,IAAI,eAAe,GAAG,OAAO;EAE9C,MAAM,sBAAsB,GAAG,KAC7B,iEACF;EACA,IACE,oBAAoB,WAAW,KAC/B,oBAAoB,GAAG,OAAO,WAAW,GAEzC,OAAO;EAET,MAAM,gBAAgB,oBAAoB,GAAG,OAC1C,KAAK,QAAQ,IAAI,EAAE,EACnB,QAAQ,SAAyB,OAAO,SAAS,QAAQ;EAE5D,MAAM,iBAAiB,YAAY,IAAI,mBAAmB;EAC1D,MAAM,iCAAiB,IAAI,IAAY;EACvC,IAAI,gBAAgB;GAClB,MAAM,WAAW,GAAG,KAAK,0CAA0C;GACnE,KAAK,MAAM,OAAO,SAAS,IAAI,UAAU,CAAC,GACxC,IAAI,OAAO,IAAI,OAAO,UAAU,eAAe,IAAI,IAAI,EAAE;EAE7D;EAEA,MAAM,UAAU,cAAc,QAAQ,SAAS,CAAC,eAAe,IAAI,IAAI,CAAC;EACxE,IAAI,QAAQ,WAAW,GAAG,OAAO;EAEjC,IAAI,CAAC,gBACH,GAAG,IACD,2GAGF;EAGF,KAAK,MAAM,aAAa,SAAS;GAI/B,MAAM,QAHc,GAAG,KACrB,wBAAwB,gBAAgB,SAAS,GAErC,EAAY,IAAI,OAAO,KAAK,MAAM;GAChD,GAAG,IACD,oFACA;IAAE,SAAS;IAAW,UAAU;GAAM,CACxC;EACF;EAEA,OAAO,GAAG,OAAO;CACnB,UAAU;EACR,GAAG,MAAM;CACX;AACF;AAEA,IAAI,eAA4C;;;;;;;;AAShD,eAAsB,UAAU,SAAwC;CACtE,IAAI,CAAC,cAAc;EACjB,MAAM,QAAQ,WAAW,gBAAgB,QAAQ,QAAQ,EAAE;EAC3D,gBAAgB,YAAY;GAC1B,MAAM,kBAAkB,GAAG,KAAK,kBAAkB;GAClD,MAAM,YAAa,WAAyC;GAC5D,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,4CAA4C;GAE9D,OAAO,UAAU,EAAE,aAAa,SAAS,GAAG,KAAK,QAAQ,OAAO,CAAC;EACnE,GAAG;EACH,aAAa,YAAY;GAEvB,eAAe;EACjB,CAAC;CACH;CACA,OAAO;AACT;;;;;;;;;;;;AAaA,eAAsB,uBACpB,OACA,SACqB;CACrB,IAAI,CAAC,gBAAgB,KAAK,GAAG,OAAO;CACpC,IAAI;EAEF,OAAO,2BAA2B,MADhB,UAAU,OAAO,GACI,KAAK;CAC9C,SAAS,OAAO;EACd,QAAQ,KACN,gFACA,KACF;EACA,OAAO;CACT;AACF;;;ACjJA,IAAM,iBAAiB;CAAC;CAAG;CAAI;CAAI;CAAI;AAAE;;;;;;;;;;;;;;;AAgBzC,SAAgB,sBAAsB,MAA8B;CAGlE,IAAI,KAAK,SAAS,KAAK,KAAK,OAAO,MAAQ,KAAK,OAAO,IAAM,OAAO;CACpE,IAAI,KAAK,SAAS,GAChB,MAAM,IAAI,MAAM,qDAAqD;CAGvE,MAAM,oBADQ,KAAK,MACiB,IAAK;CACzC,IAAI,qBAAqB,eAAe,QACtC,MAAM,IAAI,MACR,iEAAiE,kBAAkB,EACrF;CAEF,MAAM,eAAe,IAAI,eAAe;CACxC,IAAI,KAAK,SAAS,cAChB,MAAM,IAAI,MAAM,uDAAuD;CAEzE,OAAO,KAAK,SAAS,YAAY;AACnC;;;;;;;;;;;;AAaA,SAAgB,0BAA0B,MAA2B;CACnE,OACE,KAAK,UAAU,KACf,KAAK,OAAO,MACZ,KAAK,OAAO,OACX,KAAK,KAAK,QAAU;AAEzB;;;;;;;;;;;;;;;;AAiBA,SAAgB,UAAU,OAA6B;CACrD,MAAM,OAAO,IAAI,SAAS,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU;CAC1E,IAAI,SAAS;CAEb,SAAS,eAAyB;EAChC,MAAM,SAAS,KAAK,SAAS,MAAM,MAAM;EACzC,UAAU;EACV,MAAM,UAAU,KAAK,UAAU,QAAQ,MAAM;EAC7C,UAAU;EAKV,MAAM,YAAY,UAAU,gBAAgB;EAC5C,MAAM,YAAY,UAAU,gBAAgB;EAC5C,MAAM,WAAW,UAAU,eAAgB;EAC3C,MAAM,WAAW,UAAU;EAC3B,MAAM,WAAW,KAAK,MAAO,WAAW,MAAQ,GAAI;EACpD,MAAM,OAAO,WAAW;EACxB,MAAM,OAAO,YAAY,aAAa,KAAK,aAAa;EACxD,MAAM,OAAO,YAAY,aAAa,KAAK,aAAa;EAIxD,IAAI,SAAS,UAAU;EAEvB,MAAM,qBAA+B;GACnC,MAAM,IAAI,KAAK,WAAW,QAAQ,MAAM;GACxC,UAAU;GACV,MAAM,IAAI,KAAK,WAAW,QAAQ,MAAM;GACxC,UAAU;GACV,IAAI;GACJ,IAAI,MAAM;IACR,IAAI,KAAK,WAAW,QAAQ,MAAM;IAClC,UAAU;GACZ;GACA,IAAI,MAAM,UAAU;GACpB,OAAO,MAAM,KAAA,IAAY,CAAC,GAAG,CAAC,IAAI;IAAC;IAAG;IAAG;GAAC;EAC5C;EAEA,MAAM,sBAAkC;GACtC,MAAM,QAAQ,KAAK,UAAU,QAAQ,MAAM;GAC3C,UAAU;GACV,MAAM,YAAwB,CAAC;GAC/B,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG,UAAU,KAAK,aAAa,CAAC;GAChE,OAAO;EACT;EAEA,MAAM,kBAAgC;GACpC,MAAM,QAAQ,KAAK,UAAU,QAAQ,MAAM;GAC3C,UAAU;GACV,MAAM,QAAsB,CAAC;GAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG,MAAM,KAAK,cAAc,CAAC;GAC7D,OAAO;EACT;EAEA,MAAM,qBAAiC;GACrC,MAAM,QAAQ,KAAK,UAAU,QAAQ,MAAM;GAC3C,UAAU;GACV,MAAM,WAAuB,CAAC;GAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG,SAAS,KAAK,aAAa,CAAC;GAC/D,OAAO;EACT;EAEA,QAAQ,MAAR;GACE,KAAK,GACH,OAAO;IAAE,MAAM;IAAS,aAAa,aAAa;GAAE;GACtD,KAAK,GACH,OAAO;IAAE,MAAM;IAAc,aAAa,cAAc;GAAE;GAC5D,KAAK,GACH,OAAO;IAAE,MAAM;IAAW,aAAa,UAAU;GAAE;GACrD,KAAK,GAEH,OAAO;IACL,MAAM;IACN,aAHa,aAGA,EAAO,KACjB,MAAO,EAAgC,WAC1C;GACF;GAEF,KAAK,GAEH,OAAO;IACL,MAAM;IACN,aAHY,aAGC,EAAM,KAChB,MAAO,EAAkC,WAC5C;GACF;GAEF,KAAK,GAEH,OAAO;IACL,MAAM;IACN,aAHe,aAGF,EAAS,KACnB,MAAO,EAAoC,WAC9C;GACF;GAEF,KAAK,GACH,OAAO;IAAE,MAAM;IAAsB,YAAY,aAAa;GAAE;GAClE,KAAK,IAKH,OAAO;IACL,MAAM;IACN,aAHc,aAGD,EAAQ,KAClB,UAAW,MAAwC,WACtD;GACF;GAEF,KAAK,IAMH,OAAO;IACL,MAAM;IACN,aAHgB,aAGH,EAAU,KACpB,aACE,SAA2C,WAChD;GACF;GAEF,KAAK,IAEH,OAAO;IAAE,MAAM;IAAW,aAAa,UAAU;GAAE;GACrD,SAGE,MAAM,IAAI,MACR,iCAAiC,OAC/B,QAAQ,KAAK,QAAQ,KACjB,2CACA,GACL,EACH;EACJ;CACF;CAEA,OAAO,aAAa;AACtB;;;;;;AAOA,SAAS,aAAa,IAAsC;CAI1D,IAAI,CAAC,YAAY,IAAI,uBAAuB,GAAG,OAAO,CAAC;CACvD,IAAI,CAAC,YAAY,IAAI,eAAe,GAAG,OAAO,CAAC;CAa/C,QAZe,GAAG,KAKhB;;;;sBAMW,EAAO,IAAI,UAAU,CAAC,GACvB,KAAK,QAAQ;EACvB,MAAM,QAAQ,OAAO,IAAI,EAAE;EAC3B,OAAO;GACL;GACA,gBAAgB,OAAO,IAAI,EAAE;GAC7B,OAAO,IAAI,MAAM,OAAO,OAAO,OAAO,IAAI,EAAE;GAC5C,UAAU,aAAa,IAAI,KAAK;EAClC;CACF,CAAC;AACH;;AAGA,SAAS,aAAa,IAAmB,OAA8B;CACrE,IAAI,WAA0B;CAC9B,KAAK,MAAM,QAAQ,GAAG,KAAK,qBAAqB,gBAAgB,KAAK,EAAE,EAAE,EAAE,IACvE,UAAU,CAAC,GAEb,IAAI,KAAK,OAAO,GAAG,WAAW,OAAO,KAAK,EAAE;CAE9C,OAAO;AACT;;;;;;AAOA,SAAS,YACP,IACA,aACwB;CACxB,MAAM,SAAS,aAAa,EAAE;CAC9B,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,IAAI,CAAC,aAAa,OAAO,OAAO;CAChC,MAAM,SAAS,YAAY,YAAY;CACvC,OAAO,OAAO,MAAM,UAAU,MAAM,MAAM,YAAY,MAAM,MAAM,KAAK;AACzE;AAIA,IAAM,mBAAmB,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;;;;;;;;;;;;;;AAe7C,SAAS,iBACP,IACA,OACe;CAEf,IACE,SAAS,QACT,UAAU,KACV,UAAU,MACV,iBAAiB,IAAI,KAAK,GAE1B,OAAO;CAET,IAAI,CAAC,YAAY,IAAI,sBAAsB,GAAG,OAAO;CACrD,MAAM,MAAM,GAAG,KACb;oDAEA,EAAE,OAAO,MAAM,CACjB,EAAE,IAAI,OAAO;CACb,IAAI,CAAC,KAAK,OAAO;CACjB,MAAM,eAAe,OAAO,IAAI,MAAM,EAAE,EAAE,YAAY;CACtD,MAAM,OAAO,IAAI,MAAM,OAAO,OAAO,OAAO,IAAI,EAAE;CAIlD,IACE,iBAAiB,UACjB,QAAQ,QACR,OAAO,UAAU,IAAI,KACrB,OAAO,GAEP,OAAO,iBAAiB,IAAI,IAAI,IAAI,OAAO,QAAQ;CAErD,OAAO,kBAAkB,IAAI,KAAK;AACpC;;;;;;;AAQA,SAAS,kBAAkB,IAAmB,OAA8B;CAC1E,IAAI;CACJ,IAAI;EACF,QAAQ,GAAG,KACT,kEACA,EAAE,OAAO,MAAM,CACjB,EAAE,IAAI,OAAO,KAAK;CACpB,QAAQ;EACN,OAAO;CACT;CACA,MAAM,aAAa,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;CAG9D,IAAI,CAAC,cAAc,WAAW,YAAY,MAAM,aAAa,OAAO;CACpE,OAAO;AACT;;AAGA,SAAS,kBACP,IACA,OACoC;CACpC,MAAM,SAAS,GAAG,KAAK,iBAAiB,gBAAgB,MAAM,KAAK,GAAG;CACtE,MAAM,WAAuC,CAAC;CAC9C,IAAI,OAAO,SAAS,GAAG;EACrB,MAAM,UAAU,OAAO,GAAG;EAI1B,MAAM,eAAe,MAAM,eAAe,YAAY;EACtD,MAAM,gBAAgB,QAAQ,WAC3B,WAAW,OAAO,YAAY,MAAM,YACvC;EAIA,IAAI,gBAAgB,GAClB,MAAM,IAAI,MACR,qBAAqB,MAAM,MAAM,6CACpB,MAAM,eAAe,GACpC;EAEF,MAAM,UAAU,MAAM,WAAW,QAAQ,QAAQ,MAAM,QAAQ,IAAI;EAEnE,KAAK,MAAM,OAAO,OAAO,GAAG,QAAQ;GAClC,MAAM,aAAsC,CAAC;GAC7C,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,GAAG;IAC1C,IAAI,MAAM,iBAAiB,MAAM,SAAS;IAC1C,MAAM,QAAQ,IAAI;IAGlB,IAAI,iBAAiB,YAAY;IACjC,WAAW,QAAQ,MAAM;GAC3B;GAEA,MAAM,cAAc,IAAI;GACxB,IAAI,WAA4B;GAChC,IAAI,uBAAuB,cAAc,YAAY,SAAS,GAC5D,IAAI;IACF,MAAM,MAAM,sBAAsB,WAAW;IAE7C,WACE,0BAA0B,WAAW,KAAK,IAAI,WAAW,IACrD,OACA,UAAU,GAAG;GACrB,SAAS,OAAO;IAKd,QAAQ,KACN,4EAA4E,MAAM,MAAM,KACxF,KACF;GACF;GAEF,SAAS,KAAK;IAAE,MAAM;IAAW;IAAU;GAAW,CAAC;EACzD;CACF;CACA,OAAO;EAAE,MAAM;EAAqB;CAAS;AAC/C;;;;;;;;;AAsBA,SAAgB,yBACd,KACA,OACU;CACV,MAAM,KAAK,IAAI,IAAI,SAAS,KAAK;CACjC,IAAI;EACF,OAAO,aAAa,EAAE,EAAE,KAAK,UAAU,MAAM,KAAK;CACpD,UAAU;EACR,GAAG,MAAM;CACX;AACF;;;;;;;;;;;AAYA,SAAgB,mBACd,KACA,OACA,aACsB;CACtB,MAAM,KAAK,IAAI,IAAI,SAAS,KAAK;CACjC,IAAI;EACF,MAAM,QAAQ,YAAY,IAAI,WAAW;EACzC,IAAI,CAAC,OACH,MAAM,IAAI,MACR,cACI,0CAA0C,YAAY,MACtD,mDACN;EAEF,OAAO;GACL,mBAAmB,kBAAkB,IAAI,KAAK;GAC9C,WAAW,iBAAiB,IAAI,MAAM,KAAK;EAC7C;CACF,UAAU;EACR,GAAG,MAAM;CACX;AACF;;;;;;;;;AAUA,eAAsB,qBACpB,OACA,SACmB;CAEnB,OAAO,yBAAyB,MADd,UAAU,OAAO,GACE,KAAK;AAC5C;;;;;;;;;;;AAYA,eAAsB,eACpB,OACA,aACA,SAC+B;CAE/B,OAAO,mBAAmB,MADR,UAAU,OAAO,GACJ,OAAO,WAAW;AACnD;;;;;;;;;;;;;;;;;;;;;;;ACniBA,SAAgB,wBACd,YACY;CACZ,MAAM,UAAU,IAAI,YAAY;CAChC,MAAM,SAAuB,CAAC;CAC9B,IAAI,QAAQ;CACZ,MAAM,SAAS,SAAuB;EACpC,MAAM,QAAQ,QAAQ,OAAO,IAAI;EACjC,OAAO,KAAK,KAAK;EACjB,SAAS,MAAM;CACjB;CAEA,MAAM,EAAE,UAAU,GAAG,SAAS;CAK9B,MADa,KAAK,UAAU;EAAE,GAAG;EAAM,UAAU,CAAC;CAAE,CAC9C,EAAK,MAAM,GAAG,EAAE,CAAC;CACvB,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,GACpD,MACE,UAAU,IACN,KAAK,UAAU,SAAS,MAAM,IAC9B,IAAI,KAAK,UAAU,SAAS,MAAM,GACxC;CAEF,MAAM,IAAI;CAEV,MAAM,MAAM,IAAI,WAAW,KAAK;CAChC,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,IAAI,OAAO,MAAM;EACrB,UAAU,MAAM;CAClB;CACA,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,uBACd,YACA,MACsC;CAItC,IAAI,CAAC,OAAO,cAAc,IAAI,KAAK,QAAQ,GACzC,MAAM,IAAI,MAAM,wCAAwC;CAE1D,MAAM,EAAE,UAAU,GAAG,SAAS;CAC9B,IAAI,SAAS,WAAW,GAAG,OAAO,CAAC;EAAE,GAAG;EAAM,UAAU,CAAC;CAAE,CAAC;CAC5D,MAAM,SAA+C,CAAC;CACtD,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,MACpD,OAAO,KAAK;EAAE,GAAG;EAAM,UAAU,SAAS,MAAM,OAAO,QAAQ,IAAI;CAAE,CAAC;CAExE,OAAO;AACT;;;;;;;AClFA,IAAM,iBAAiB;AACvB,IAAM,aAAa;AAGnB,IAAI;AAEJ,SAAS,cAAc;CACrB,IAAI,CAAC,gBAAgB;EACnB,iBAAiB,QAAQ,IAAI,CAAC,cAAc,cAAc,GAAG,cAAc,UAAU,CAAC,CAAC,EAAE,MACtF,CAAC,KAAK,YAAmB;GACxB,WAAW,IAAI,WAAW;GAC1B,eAAe,MAAM,iBAAiB,MAAM,SAAS;EACvD,EACF;EACA,eAAe,YAAY;GACzB,iBAAiB,KAAA;EACnB,CAAC;CACH;CACA,OAAO;AACT;;;;;;;;;;AAYA,SAAgB,aACd,GACA,GACA,GACA,SAAS,GACyB;CAClC,MAAM,IAAI,KAAK;CACf,MAAM,SAAS,QAAiB,MAAM,IAAK,MAAM;CACjD,MAAM,SAAS,QAAiB,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM,IAAK,IAAI,MAAO,EAAE,CAAC,IAAI,MAAO,KAAK;CAClG,MAAM,OAAO,MAAM,IAAI,MAAM;CAC7B,MAAM,OAAO,MAAM,IAAI,IAAI,MAAM;CACjC,MAAM,QAAQ,MAAM,IAAI,MAAM;CAE9B,OAAO;EAAC;EADM,MAAM,IAAI,IAAI,MACd;EAAO;EAAM;CAAK;AAClC;;;;;;;;;;;;;;AAeA,eAAsB,uBACpB,UACA,WACA,GACA,GACA,GACqB;CACrB,IAAI,SAAS,WAAW,GAAG,OAAO,IAAI,WAAW,CAAC;CAElD,MAAM,EAAE,WAAW,kBAAkB,MAAM,YAAY;CAKvD,MAAM,OAJQ,UACZ;EAAE,MAAM;EAAqB;CAAS,GACtC;EAAE,SAAS;EAAG,cAAc;EAAG,gBAAgB;EAAG,QAAQ;EAAI,WAAW;CAAE,CAEhE,EAAM,QAAQ,GAAG,GAAG,CAAC;CAClC,IAAI,CAAC,MAAM,OAAO,IAAI,WAAW,CAAC;CAElC,MAAM,UAAU,cAAc,GAAG,YAAY,KAAK,GAAG,EAAE,SAAS,EAAE,CAAC;CACnE,OAAO,IAAI,WAAW,OAAO;AAC/B;;;;ACnFA,SAAS,eAAe,WAA2B;CACjD,OAAO,UAAU,QAAQ,aAAa,EAAE;AAC1C;;;;;;;;;AAUA,SAAgB,qBAAqB,WAA4B;CAC/D,MAAM,WAAW,UAAU,MAAM,UAAU,YAAY,GAAG,IAAI,CAAC;CAC/D,OAAO,UAAU,WAAW,WAAW,KAAK,SAAS,WAAW,IAAI;AACtE;;;;;;;;AASA,IAAa,+BAA+B,IAAI,IAAI;CAClD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAUD,SAAS,eAAe,MAAsB;CAC5C,MAAM,MAAM,KAAK,YAAY,GAAG;CAChC,OAAO,MAAM,IAAI,KAAK,KAAK,MAAM,MAAM,CAAC,EAAE,YAAY;AACxD;AAEA,SAAS,cAAc,MAAsB;CAC3C,MAAM,MAAM,KAAK,YAAY,GAAG;CAChC,QAAQ,MAAM,IAAI,OAAO,KAAK,MAAM,GAAG,GAAG,GAAG,YAAY;AAC3D;;;;;;;;;;;;;;AAeA,SAAgB,yBACd,OAC0B;CAC1B,MAAM,WAAW,MAAM,QAAQ,MAAM,UAAU,KAAK,EAAE,IAAI,CAAC;CAC3D,MAAM,0BAAU,IAAI,IAAO;CAC3B,MAAM,kCAAkB,IAAI,IAAY;CAExC,KAAK,MAAM,OAAO,UAAU;EAC1B,MAAM,OAAO,cAAc,IAAI,IAAI;EACnC,MAAM,aAAa,MAAM,QACtB,MACC,MAAM,OACN,CAAC,UAAU,KAAK,EAAE,IAAI,KACtB,cAAc,EAAE,IAAI,MAAM,QAC1B,6BAA6B,IAAI,eAAe,EAAE,IAAI,CAAC,CAC3D;EACA,WAAW,SAAS,MAAM,QAAQ,IAAI,CAAC,CAAC;EACxC,gBAAgB,IAAI,KAAK,UAAU;CACrC;CAEA,MAAM,SAAmC,CAAC;CAC1C,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,QAAQ,IAAI,IAAI,GAAG;EACvB,OAAO,KAAK;GAAE;GAAM,YAAY,gBAAgB,IAAI,IAAI,KAAK,CAAC;EAAE,CAAC;CACnE;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;AAuBA,eAAsB,wBACpB,KACA,UACA,UAC8B;CAC9B,MAAM,QAAQ,UAAU,GAAG;CAC3B,MAAM,WAAW,OAAO,KAAK,KAAK,EAAE,MACjC,SAAS,UAAU,KAAK,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAC9D;CACA,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,2CAA2C;CAG7D,MAAM,OAAO,eAAe,QAAQ;CACpC,IAAI,UAAU;CACd,IAAI,SAAwB;CAC5B,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,KAAK,GAAG;EAGlD,IAAI,qBAAqB,KAAK,KAAK,eAAe,KAAK,MAAM,MAAM;EACnE,MAAM,YAAY,MAAM,MAAM,MAAM,YAAY,GAAG,CAAC,EAAE,YAAY;EAClE,MAAM,iBAAiB,GAAG,WAAW;EAIrC,IAAI,cAAc,QAAQ;GACxB,MAAM,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK,EAAE,KAAK;GAClD,IAAI,MAAM,SAAS;EACrB;EACA,MAAM,SAAS,gBAAgB,KAAK;EACpC,IAAI,cAAc,QAAQ,UAAU;CACtC;CAEA,OAAO;EAAE;EAAS;CAAO;AAC3B;;;;;;;;;;;;;;;;;;;AAoCA,eAAsB,uBACpB,KACA,YACA,UACA,UACiB;CACjB,MAAM,UAAU,GAAG,SAAS;CAC5B,MAAM,SAAS,SAAS,GAAG;CAC3B,KAAK,MAAM,EAAE,WAAW,WAAW,YAAY;EAC7C,MAAM,OAAO,UAAU,WAAW,GAAG,IAAI,YAAY,IAAI,aAAa,YAAY;EAClF,IAAI,QAAQ,QAAQ;EACpB,MAAM,SAAS,GAAG,WAAW,OAAO,KAAK;CAC3C;CACA,OAAO;AACT;;;;;;;;;;;;;;;;ACxKA,SAAgB,aAAa,YAA0C;CACrE,MAAM,aAAa,WAChB,QAAQ,SAAS,UAAU,KAAK,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,EACpE,KAAK;CACR,OACE,WAAW,MACR,SAAS,KAAK,MAAM,KAAK,YAAY,GAAG,IAAI,CAAC,EAAE,YAAY,MAAM,SACpE,KAAK,WAAW;AAEpB;;;;;;;;AASA,SAAgB,cAAc,KAA8B;CAC1D,IAAI;CACJ,IAAI;EACF,QAAQ,UAAU,GAAG;CACvB,QAAQ;EAGN,MAAM,IAAI,MAAM,uEAAuE;CACzF;CACA,MAAM,YAAY,aAAa,OAAO,KAAK,KAAK,CAAC;CACjD,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,2CAA2C;CAE7D,OAAO;EAAE;EAAW,OAAO,MAAM;CAAW;AAC9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA,SAAgB,oBACd,cACA,SACA,gBACe;CACf,IAAI,CAAC,cAAc,OAAO;CAE1B,IAAI;CACJ,IAAI;EACF,WAAW,KAAK,MAAM,YAAY;CACpC,QAAQ;EAGN,OAAO;CACT;CAEA,MAAM,SAAS,uBAAuB,UAAU,cAAc;CAC9D,IAAI,CAAC,UAAU,EAAE,SAAS,SAAS,OAAO;CAE1C,MAAM,MAAO,OAA6B;CAE1C,IAAI,QAAQ,QAAQ,QAAQ,KAAA,GAAW,OAAO;CAE9C,MAAM,WAAW,UAAU,GAAG;CAC9B,IAAI,CAAC,YAAY,QAAQ,QAAQ,GAAG,OAAO;CAC3C,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAS,uBACP,UACA,gBACe;CACf,MAAM,UAAW,UAAoC;CACrD,IAAI,CAAC,WAAW,OAAO,YAAY,UAAU,OAAO;CACpD,MAAM,UAAU,OAAO,QAAQ,OAAkC,EAAE,QAChE,UACC,OAAO,MAAM,OAAO,YAAY,MAAM,OAAO,IACjD;CACA,IAAI,QAAQ,WAAW,GAAG,OAAO;CAEjC,MAAM,UAAW,SAA0C;CAC3D,KAAK,MAAM,UAAU,CAAC,gBAAgB,OAAO,GAAG;EAC9C,IAAI,OAAO,WAAW,UAAU;EAChC,MAAM,QAAQ,QAAQ,MAAM,CAAC,UAAU,SAAS,MAAM;EACtD,IAAI,OAAO,OAAO,MAAM;CAC1B;CACA,OAAO,QAAQ,GAAG;AACpB;;;;;;;AAQA,SAAS,UAAU,KAA6B;CAC9C,IAAI,OAAO,QAAQ,UAAU,OAAO,IAAI,KAAK,KAAK;CAClD,IAAI,OAAO,QAAQ,UAAU,OAAO;CAEpC,MAAM,KAAM,IAAyB;CACrC,MAAM,YAAa,IAAgC;CACnD,MAAM,OAAQ,IAA2B;CACzC,IACE,OAAO,cAAc,aACpB,OAAO,SAAS,YAAY,OAAO,SAAS,WAE7C,OAAO,GAAG,UAAU,KAAK,EAAE,YAAY,EAAE,GAAG,OAAO,IAAI,EAAE,KAAK;CAKhE,OAAO,KAAK,UAAU,GAAG;AAC3B;;;;;;;;AC3HA,IAAM,yBAAyB,IAAI,IAAI;CAAC;CAAI;CAAI;AAAE,CAAC;;;;;;;;;;;;;;;;AAiBnD,SAAgB,6BAA6B,OAAyB;CACpE,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CACrE,MAAM,QAAQ,QAAQ,YAAY;CAIlC,IAAI,EAFF,MAAM,SAAS,qBAAqB,KACnC,MAAM,SAAS,UAAU,KAAK,MAAM,SAAS,eAAe,IACxC,OAAO;CAG9B,MAAM,UAAU,QAAQ,MAAM,mBAAmB;CACjD,IAAI,SACF,OAAO,uBAAuB,IAAI,OAAO,QAAQ,EAAE,IAAI,GAAI;CAK7D,OAAO,+BAA+B,KAAK,OAAO;AACpD;;;;;;AAOA,SAAS,eAAe,OAAmC;CACzD,IAAI,iBAAiB,YAAY,OAAO,MAAM,SAAS,IAAI,QAAQ;CACnE,IAAI,OAAO,UAAU,YAAY,MAAM,SAAS,GAC9C,IAAI;EACF,OAAO,WAAW,KAAK,KAAK,KAAK,IAAI,SAAS,KAAK,WAAW,CAAC,CAAC;CAClE,QAAQ;EACN,OAAO;CACT;CAEF,OAAO;AACT;;AAGA,SAAS,iBAAiB,OAAyB;CACjD,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO;CAClD,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,cAAc,OAAO,KAAK,CAAC,IAAI,OAAO,KAAK,IAAI,MAAM,SAAS;CAE9E,IAAI,iBAAiB,MAAM,OAAO,MAAM,YAAY;CACpD,IAAI,iBAAiB,YAAY,OAAO;CACxC,IAAI,OAAO,UAAU,UACnB,IAAI;EACF,OAAO,KAAK,MACV,KAAK,UAAU,QAAQ,MAAM,MAC3B,OAAO,MAAM,WACT,OAAO,cAAc,OAAO,CAAC,CAAC,IAC5B,OAAO,CAAC,IACR,EAAE,SAAS,IACb,CACN,CACF;CACF,QAAQ;EACN,OAAO,OAAO,KAAK;CACrB;CAEF,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,2BACd,MACA,WACoC;CAuBpC,OAAO;EAAE,MAAM;EAAqB,UAtBnB,KAAK,KAAK,QAAQ;GACjC,MAAM,QAAQ,eAAe,IAAI,UAAU;GAC3C,IAAI,WAA4B;GAChC,IAAI,OACF,IAAI;IACF,WAAW,UAAU,KAAK;GAC5B,QAAQ;IAEN,WAAW;GACb;GAEF,MAAM,aAAsC,CAAC;GAC7C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAAG;IAC9C,IAAI,QAAQ,aAAa,iBAAiB,YAAY;IACtD,WAAW,OAAO,iBAAiB,KAAK;GAC1C;GACA,OAAO;IACL,MAAM;IACN;IACA;GACF;EACF,CACoC;CAAS;AAC/C;;;;;;;;;;;;;;;;;;ACtDA,IAAM,aAAa;;;;;;;;;AAUnB,IAAM,0BAA0B;AAEhC,SAAS,eAAe,KAAsB;CAC5C,QAAQ,IAAI,YAAY,GAAxB;EACE,KAAK;EACL,KAAK;EACL,KAAK,aACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;;AAgCA,IAAM,aAAN,MAAiB;CACf,QAAkC,QAAQ,QAAQ;;;;;;;;;CAUlD,QAAW,MAAwB,QAAkC;EACnE,MAAM,MAAM,KAAK,MAAM,WAAW;GAChC,IAAI,QAAQ,SACV,MAAM,IAAI,aAAa,8BAA8B,YAAY;GAEnE,OAAO,KAAK;EACd,CAAC;EACD,KAAK,QAAQ,IAAI,YAAY,KAAA,CAAS;EACtC,OAAO;CACT;AACF;;;;AAwBA,SAAS,cAAc,OAAqB;CAC1C,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO;CAClD,QAAQ,OAAO,OAAf;EACE,KAAK,UACH,OAAO,OAAO,cAAc,OAAO,KAAK,CAAC,IACrC,OAAO,KAAK,IACZ,MAAM,SAAS;EACrB,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO;EACT,KAAK;GACH,IAAI,iBAAiB,MAAM,OAAO,MAAM,YAAY;GACpD,IAAI,iBAAiB,YAAY,OAAO;GACxC,IAAI;IACF,OAAO,KAAK,MACV,KAAK,UAAU,QAAQ,MAAM,MAC3B,OAAO,MAAM,WACT,OAAO,cAAc,OAAO,CAAC,CAAC,IAC5B,OAAO,CAAC,IACR,EAAE,SAAS,IACb,CACN,CACF;GACF,QAAQ;IACN,OAAO,OAAO,KAAK;GACrB;EACF,SACE,OAAO,OAAO,KAAK;CACvB;AACF;AAEA,SAAS,gBAAgB,OAAwB;CAC/C,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;CAClD,OAAO;AACT;;;;AAKA,SAAS,qBAAqB,MAAgC;CAC5D,MAAM,QAAQ,KAAK,YAAY;CAC/B,IAAI,MAAM,SAAS,OAAO,GAAG,OAAO;CACpC,IAAI,MAAM,SAAS,YAAY,GAAG,OAAO;CACzC,IAAI,MAAM,SAAS,SAAS,GAAG,OAAO;CACtC,OAAO,MAAM,SAAS,oBAAoB,IAAI,UAAU;AAC1D;;;;;AAMA,IAAa,eAAb,MAA6C;CAC3C;CACA,SAAiB,IAAI,WAAW;CAChC,0BAAkB,IAAI,IAAuB;;;;;;;CAO7C,+BAAuB,IAAI,IAAkB;;;;;;CAM7C,mCAA2B,IAAI,IAAwC;;;;;;CAMvE,+BAAuB,IAAI,IAAoC;;;;;;CAM/D,gCAAwB,IAAI,IAAoB;CAChD;;CAEA,gBAAwB;;;;;;;CAQxB,YAAY,QAAsB,cAAuB;EACvD,KAAK,UAAU;EACf,KAAK,gBAAgB;CACvB;;CAGA,IAAI,cAAuB;EACzB,OAAO,KAAK,QAAQ;CACtB;;CAGA,IAAI,UAAkB;EACpB,OAAO,KAAK,QAAQ;CACtB;;CAGA,OACE,QACA,WACA,SACwB;EACxB,OAAO,KAAK,OAAO,QAAQ,YAAY;GACrC,MAAM,WACJ,QAAQ,SAAS,YAAY,QAAQ,WAAW;GAClD,MAAM,OAAkB;IACtB,iBAAiB,CAAC;IAClB,UAAU;IACV;GACF;GAEA,IAAI;GAGJ,IAAI,YAA2B;GAI/B,IAAI,QAAQ,WAAW,gBAAgB,CAAC,UAAU;IAChD,MAAM,QAAQ,MAAM,KAAK,oBAAoB,MAAM;IACnD,WAAW,MAAM;IACjB,MAAM,KAAK,2BAA2B,WAAW,OAAO,OAAO;GACjE,OAAO;IACL,MAAM,OAAO,MAAM,KAAK,gBAAgB,QAAQ,WAAW,OAAO;IAClE,WACE,OAAO,SAAS,eAAe,kBAAkB,OAC7C,OAAO,OACP,MAAM,gBAAgB,MAAgB;IAC5C,IAAI,UACF,YAAY,MAAM,KAAK,kBAAkB,WAAW,MAAM,OAAO;SAEjE,IAAI;KACF,MAAM,KAAK,aAAa,WAAW,MAAM,OAAO;IAClD,SAAS,KAAK;KAUZ,IAAI,CAAC,MAPiB,KAAK,oBACzB,KACA,QACA,WACA,SACA,IACF,GACc,MAAM;IACtB;GAEJ;GAEA,MAAM,UAAU,MAAM,KAAK,eAAe,SAAS;GAOnD,KAAK,aACH,YAAY,YACR,KAAA,IACA,QAAQ,MAAM,MAAM,qBAAqB,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG;GACjE,KAAK,kBAAkB,QACpB,QACE,MACC,EAAE,SAAS,cACX,EAAE,SAAS,eACX,EAAE,SAAS,KAAK,UACpB,EACC,KAAK,MAAM,EAAE,IAAI;GACpB,KAAK,QAAQ,IAAI,WAAW,IAAI;GAGhC,OAAO;IACL,GAAG,MAFiB,KAAK,WAAW,WAAW,IAAI;IAGnD;IACA,QAAQ,CAAC,GAAG,KAAK,eAAe;IAChC;IACA;GACF;EACF,CAAC;CACH;;CAGA,cAAc,WAA+C;EAC3D,OAAO,KAAK,OAAO,QAAQ,YAAY;GACrC,MAAM,OAAO,KAAK,cAAc,SAAS;GAYzC,OAAO;IAAE,MAAM;IAAqB,WARR,MAHP,KAAK,QAAQ,KAAK,MACrC,mBAAmB,WAAW,KAAK,eAAe,CACpD,GACmC,QAAQ,EAAE,KAAK,QAAQ;KACxD,MAAM,WAAW,KAAK,MAAM,OAAO,IAAI,SAAS,CAAC;KACjD,MAAM,aAAsC,CAAC;KAC7C,KAAK,MAAM,UAAU,KAAK,iBACxB,WAAW,UAAU,cAAc,IAAI,OAAO;KAEhD,OAAO;MAAE,MAAM;MAAW;MAAU;KAAW;IACjD,CACoC;GAAS;EAC/C,CAAC;CACH;;CAGA,kBAAkB,WAAmB,UAAsC;EACzE,OAAO,KAAK,OAAO,QAAQ,YAAY;GAErC,IAAI,CADS,KAAK,cAAc,SAC3B,EAAK,gBAAgB,SAAS,QAAQ,GAAG,OAAO,CAAC;GAItD,QAAO,MAHc,KAAK,QAAQ,KAAK,MACrC,oBAAoB,WAAW,QAAQ,CACzC,GACc,QAAQ,EAAE,KAAK,QAAQ,cAAc,IAAI,OAAO,CAAC;EACjE,CAAC;CACH;;CAGA,iBACE,YACA,WAC4B;EAC5B,OAAO,KAAK,OAAO,QAAQ,YAAY;GACrC,MAAM,WAAW,WAAW;GAK5B,MAAM,YAA+B;IACnC,MAAM;IACN,UAAU,SAAS,KAAK,SAAS,WAAW;KAC1C,MAAM;KACN,YAAY,GAAG,aAAa,MAAM;KAClC,UAAU,QAAQ;IACpB,EAAE;GACJ;GACA,MAAM,cAAc,aAAa,KAAK,gBAAgB;GACtD,MAAM,KAAK,QAAQ,GAAG,mBACpB,aACA,wBAAwB,SAAS,CACnC;GACA,IAAI;IACF,MAAM,SAAS,MAAM,KAAK,QAAQ,KAAK,MACrC,UAAU,WAAW,UAAU,EAAE,2CACI,aAAa,SAAS,EAAE,+DAC3C,aAAa,WAAW,EAAE,yBAC9C;IAGA,MAAM,8BAAc,IAAI,IAAsB;IAC9C,KAAK,MAAM,OAAO,OAAO,QAAQ,GAC/B,YAAY,IACV,OAAO,IAAI,GAAG,GACd,KAAK,MAAM,OAAO,IAAI,SAAS,CAAC,CAClC;IAEF,OAAO;KACL,MAAM;KACN,UAAU,SAAS,KAAK,SAAS,WAAW;MAC1C,GAAG;MACH,UAAU,YAAY,IAAI,KAAK,KAAK,QAAQ;KAC9C,EAAE;IACJ;GACF,UAAU;IACR,MAAM,KAAK,QAAQ,GAAG,SAAS,WAAW,EAAE,YAAY,KAAA,CAAS;GACnE;EACF,CAAC;CACH;;CAGA,aAAa,WAAkC;EAC7C,OAAO,KAAK,OAAO,QAAQ,YAAY;GACrC,MAAM,OAAO,KAAK,cAAc,SAAS;GACzC,IAAI,KAAK,UAAU;GAInB,IAAI,KAAK,UAAU;IACjB,KAAK,WAAW;IAChB;GACF;GAEA,MAAM,aAAa,gBAAgB,SAAS;GAC5C,KAAK,MAAM,aAAa,WAAW,WACjC,MAAM,KAAK,QAAQ,KAAK,MAAM,SAAS;GAEzC,IAAI;IACF,MAAM,KAAK,QAAQ,KAAK,MAAM,WAAW,KAAK;GAChD,QAAQ,CAER;GACA,KAAK,WAAW;EAClB,CAAC;CACH;;CAGA,QACE,WACA,WACA,GACA,GACA,GACA,QACqB;EACrB,OAAO,KAAK,OAAO,QAAQ,YAAY;GACrC,MAAM,OAAO,KAAK,cAAc,SAAS;GAEzC,IAAI,KAAK,QAAQ,aAAa;IAC5B,MAAM,QAAQ,KAAK,WACf,mBACE,WACA,WACA,GACA,GACA,GACA,aAAa,GAAG,GAAG,GAAG,KAAK,IAAI,GAC/B,KAAK,iBACL,KAAK,UACP,IACA,aAAa,WAAW,WAAW,GAAG,GAAG,GAAG,KAAK,eAAe;IAEpE,MAAM,SAAQ,MADO,KAAK,QAAQ,KAAK,MAAM,KAAK,GAC7B,QAAQ,EAAE,IAAI;IAKnC,OAAO,QAAQ,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,CAAC;GACzD;GAGA,MAAM,OAAO,aAAa,GAAG,GAAG,GAAG,KAAK,IAAI;GAY5C,OAAO,wBARqB,MAHP,KAAK,QAAQ,KAAK,MACrC,kBAAkB,WAAW,MAAM,KAAK,eAAe,CACzD,GACmC,QAAQ,EAAE,KAAK,QAAQ;IACxD,MAAM,WAAW,KAAK,MAAM,OAAO,IAAI,SAAS,CAAC;IACjD,MAAM,aAAsC,CAAC;IAC7C,KAAK,MAAM,UAAU,KAAK,iBACxB,WAAW,UAAU,cAAc,IAAI,OAAO;IAEhD,OAAO;KAAE,MAAM;KAAW;KAAU;IAAW;GACjD,CAC8B,GAAU,WAAW,GAAG,GAAG,CAAC;EAC5D,GAAG,MAAM;CACX;;CAGA,UAAU,WAAkC;EAC1C,OAAO,KAAK,OAAO,QAAQ,YAAY;GACrC,MAAM,OAAO,KAAK,QAAQ,IAAI,SAAS;GACvC,MAAM,OAAO,MAAM,WAAW,SAAS;GACvC,MAAM,KAAK,QAAQ,KAAK,MACtB,QAAQ,KAAK,aAAa,WAAW,SAAS,GAChD;GAIA,IAAI,MAAM,WACR,IAAI,gBAAgB,KAAK,SAAS;GAEpC,KAAK,QAAQ,OAAO,SAAS;EAC/B,CAAC;CACH;;CAGA,MAAM,UAAyB;EAC7B,KAAK,MAAM,QAAQ,KAAK,QAAQ,OAAO,GACrC,IAAI,KAAK,WAAW,IAAI,gBAAgB,KAAK,SAAS;EAExD,KAAK,QAAQ,MAAM;EACnB,KAAK,MAAM,QAAQ,KAAK,aAAa,OAAO,GAC1C,MAAM,KAAK,QAAQ,GAAG,SAAS,IAAI,EAAE,YAAY,KAAA,CAAS;EAE5D,KAAK,aAAa,MAAM;EACxB,KAAK,MAAM,QAAQ,KAAK,aAAa,OAAO,GAAG;GAE7C,MAAM,OAAO,MAAM,KAAK,YAAY,KAAA,CAAS;GAC7C,IAAI,MAAM,MAAM,KAAK,QAAQ,GAAG,SAAS,IAAI,EAAE,YAAY,KAAA,CAAS;EACtE;EACA,KAAK,aAAa,MAAM;EACxB,KAAK,iBAAiB,MAAM;EAC5B,KAAK,cAAc,MAAM;EACzB,MAAM,KAAK,QAAQ,KAAK,MAAM,EAAE,YAAY,KAAA,CAAS;EACrD,MAAM,KAAK,QAAQ,GAAG,UAAU,EAAE,YAAY,KAAA,CAAS;CACzD;;;;;CAMA,MAAc,gBACZ,QACA,kBACA,SACiB;EAGjB,IAAI,QAAQ,WAAW,OACrB,OAAO,KAAK,eAAe,QAAQ,gBAAgB;EAGrD,IAAI,OAAO,WAAW,UAAU;GAG9B,MAAM,0BAA0B,MAAM;GACtC,OAAO;EACT;EAEA,MAAM,SAAS,KAAK,aAAa,IAAI,MAAM;EAC3C,IAAI,QAAQ,OAAO;EAGnB,MAAM,OAAO,GAAG,iBAAiB,IADf,QAAQ,UAAU,MAAM,iBAAiB,IAAI,MAAM,OACvB,YAAY;EAC1D,IAAI,SAAqB,IAAI,WAAW,MAAM,OAAO,YAAY,CAAC;EAKlE,IAAI,QAAQ,WAAW,cACrB,SAAS,MAAM,uBAAuB,QAAQ,KAAK,aAAa;EAQlE,IAAI,QAAQ,WAAW,eAAe,UAAU,KAAK,IAAI,GAAG;GAC1D,MAAM,EAAE,SAAS,WAAW,MAAM,wBAChC,QACA,mBACC,eAAe,UACd,KAAK,QAAQ,GAAG,mBAAmB,eAAe,KAAK,CAC3D;GAGA,IAAI,QAAQ,KAAK,cAAc,IAAI,SAAS,MAAM;GAClD,KAAK,aAAa,IAAI,QAAQ,OAAO;GACrC,OAAO;EACT;EAMA,IAAI,QAAQ,WAAW,eAAe,QAAQ,gBAAgB,QAAQ;GACpE,MAAM,aAAa,MAAM,QAAQ,IAC/B,QAAQ,eAAe,IAAI,OAAO,UAAU;IAC1C,WAAW,KAAK,KAAK,MAAM,KAAK,KAAK,YAAY,GAAG,CAAC;IACrD,OAAO,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;GAChD,EAAE,CACJ;GACA,MAAM,UAAU,MAAM,uBACpB,QACA,YACA,mBACC,eAAe,UACd,KAAK,QAAQ,GAAG,mBAAmB,eAAe,KAAK,CAC3D;GACA,KAAK,aAAa,IAAI,QAAQ,OAAO;GACrC,OAAO;EACT;EAEA,MAAM,KAAK,QAAQ,GAAG,mBAAmB,MAAM,MAAM;EACrD,KAAK,aAAa,IAAI,QAAQ,IAAI;EAClC,OAAO;CACT;;;;;;CAOA,eACE,QACA,kBACiB;EACjB,MAAM,SAAS,KAAK,aAAa,IAAI,MAAM;EAC3C,IAAI,QAAQ,OAAO;EACnB,MAAM,QAAQ,YAAY;GACxB,IAAI;GACJ,IAAI,OAAO,WAAW,UAAU;IAC9B,MAAM,0BAA0B,MAAM;IACtC,MAAM,WAAW,MAAM,MAAM,MAAM;IACnC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MACR,wBAAwB,SAAS,OAAO,GAAG,SAAS,WAAW,GACjE;IAEF,QAAQ,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC;GACrD,OACE,QAAQ,IAAI,WAAW,MAAM,OAAO,YAAY,CAAC;GAEnD,MAAM,EAAE,OAAO,QAAQ,cAAc,KAAK;GAE1C,MAAM,OAAO,GAAG,iBAAiB;GACjC,MAAM,KAAK,QAAQ,GAAG,mBAAmB,MAAM,GAAG;GAClD,OAAO;EACT,GAAG;EAEH,KAAK,YAAY,KAAK,aAAa,OAAO,MAAM,CAAC;EACjD,KAAK,aAAa,IAAI,QAAQ,IAAI;EAClC,OAAO;CACT;;;;;;CAOA,oBACE,QACqB;EACrB,MAAM,SAAS,KAAK,iBAAiB,IAAI,MAAM;EAC/C,IAAI,QAAQ,OAAO;EACnB,MAAM,SAAS,YAAY;GACzB,IAAI,OAAO,WAAW,UAAU;IAC9B,MAAM,0BAA0B,MAAM;IACtC,MAAM,WAAW,MAAM,MAAM,MAAM;IACnC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MACR,+BAA+B,SAAS,OAAO,GAAG,SAAS,WAAW,GACxE;IAEF,OAAO,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC;GACpD;GACA,OAAO,IAAI,WAAW,MAAM,OAAO,YAAY,CAAC;EAClD,GAAG;EAEH,MAAM,YAAY,KAAK,iBAAiB,OAAO,MAAM,CAAC;EACtD,KAAK,iBAAiB,IAAI,QAAQ,KAAK;EACvC,OAAO;CACT;;;;;;;;CASA,MAAc,2BACZ,WACA,OACA,SACe;EACf,MAAM,EAAE,mBAAmB,WAAW,sBAAsB,MAAM,eAChE,OACA,QAAQ,aACR,KAAK,aACP;EACA,MAAM,YAAY,QAAQ,WAAW,KAAK,KAAK;EAG/C,IAAI,kBAAkB,SAAS,WAAW,GAAG;GAC3C,MAAM,KAAK,QAAQ,KAAK,MACtB,2BAA2B,WAAW,SAAS,EAAE,8CAEnD;GACA;EACF;EAIA,MAAM,WACJ,aAAa,OACT,SACA,sBAAsB,aAAa,SAAS,EAAE;EAKpD,MAAM,UAAU,uBACd,mBACA,uBACF;EACA,IAAI;GACF,MAAM,KAAK,yBAAyB,WAAW,SAAS,QAAQ;EAClE,SAAS,OAAO;GAKd,MAAM,KAAK,QAAQ,KAChB,MAAM,wBAAwB,WAAW,SAAS,GAAG,EACrD,YAAY,KAAA,CAAS;GACxB,MAAM;EACR;CACF;;;;;CAMA,MAAc,yBACZ,WACA,SACA,UACe;EACf,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;GACtD,MAAM,cAAc,GAAG,UAAU,GAAG,MAAM;GAC1C,MAAM,KAAK,QAAQ,GAAG,mBACpB,aACA,wBAAwB,QAAQ,MAAM,CACxC;GACA,IAAI;IAEF,MAAM,SAAS,4BAA4B,SAAS,gBAAgB,WAD1C,aAAa,WAAW,EAAE;IAMpD,MAAM,KAAK,QAAQ,KAAK,MACtB,UAAU,IACN,2BAA2B,WAAW,SAAS,EAAE,MAAM,WACvD,eAAe,WAAW,SAAS,EAAE,WAAW,QACtD;GACF,UAAU;IACR,MAAM,KAAK,QAAQ,GAAG,SAAS,WAAW,EAAE,YAAY,KAAA,CAAS;GACnE;EACF;CACF;;CAGA,WACE,QACA,kBACA,SACmB;EACnB,OAAO,KAAK,OAAO,QAAQ,YAAY;GACrC,IAAI;IAIF,IAAI,QAAQ,WAAW,cAErB,OAAO,qBAAqB,MADR,KAAK,oBAAoB,MAAM,GAChB,KAAK,aAAa;IAEvD,MAAM,OAAO,MAAM,KAAK,gBACtB,QACA,kBACA,OACF;IAIA,QAAO,MAHc,KAAK,QAAQ,KAAK,MACrC,gBAAgB,SAAS,QAAQ,QAAQ,IAAI,CAAC,CAChD,GACc,QAAQ,EAAE,KAAK,QAAQ,OAAO,IAAI,IAAI,CAAC;GACvD,QAAQ;IAGN,OAAO,CAAC;GACV;EACF,CAAC;CACH;;;;;CAMA,MAAc,aACZ,WACA,MACA,SACe;EACf,MAAM,SAAS,UACb,QAAQ,QACR,SAAS,QAAQ,QAAQ,IAAI,GAC7B,QAAQ,WACV;EACA,MAAM,UAAU,MAAM,KAAK,gBAAgB,MAAM;EAEjD,MAAM,iBAAiB,MAAM,KAAK,sBAAsB,QAAQ,OAAO;EACvE,IAAI,gBAAgB;GAIlB,MAAM,YAAY,MAAM,KAAK,kBAC3B,MACA,SACA,eAAe,IACjB;GACA,IAAI;IACF,MAAM,KAAK,QAAQ,KAAK,MACtB,2BACE,WACA,QACA,gBACA,SACF,CACF;GACF,SAAS,OAAO;IAMd,IACE,QAAQ,WAAW,gBACnB,CAAC,6BAA6B,KAAK,GAEnC,MAAM;IAER,MAAM,KAAK,2BAA2B,WAAW,MAAM,OAAO;GAChE;GACA;EACF;EAEA,IAAI,QAAQ,WAAW,OAAO;GAC5B,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC,EAAE,KAAK,YAAY,GAAG,EAAE,IAAI,CAAC,CAAC;GACxE,MAAM,UAAU,iBAAiB,KAAK,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO;GACtE,IAAI,SAAS;IACX,MAAM,KAAK,QAAQ,KAAK,MACtB,sBAAsB,WAAW,QAAQ,SAAS,QAAQ,WAAW,KAAK,KAAK,IAAI,CACrF;IACA;GACF;GACA,KAAK,MAAM,CAAC,KAAK,QAAQ,sBAAsB;IAC7C,MAAM,UAAU,MAAM,IAAI,GAAG;IAC7B,MAAM,UAAU,MAAM,IAAI,GAAG;IAC7B,IAAI,WAAW,SAAS;KACtB,MAAM,KAAK,QAAQ,KAAK,MACtB,yBACE,WACA,QACA,SACA,SACA,QAAQ,WAAW,KAAK,KAAK,IAC/B,CACF;KACA;IACF;GACF;GACA,MAAM,IAAI,MACR,4DACM,iBAAiB,KAAK,IAAI,EAAE,gCACpC;EACF;EAEA,MAAM,IAAI,MACR,+CAA+C,QAAQ,OAAO,EAChE;CACF;;;;;;;;;;CAWA,MAAc,2BACZ,WACA,MACA,SACe;EACf,MAAM,YAAY,iBAAiB,MAAM,QAAQ,WAAW;EAC5D,MAAM,UAAU,MAAM,KAAK,gBAAgB,SAAS;EAIpD,MAAM,YACJ,QAAQ,MAAM,WAAW,OAAO,KAAK,YAAY,MAAM,cAAc,KACrE,QAAQ,MAAM,WAAW,mBAAmB,KAAK,OAAO,IAAI,CAAC;EAC/D,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,wDAAwD;EAI1E,MAAM,oBAAoB,4BADb,MADQ,KAAK,QAAQ,KAAK,MAAM,iBAAiB,WAAW,GACrD,QAAQ,EAAE,KAAK,QAAQ,GACU,GAAM,UAAU,IAAI;EACzE,MAAM,YACJ,QAAQ,WAAW,KAAK,KACvB,MAAM,KAAK,eACV,SAAS,QAAQ,QAAQ,IAAI,GAC7B,MAAM,KAAK,QAAQ,SAAS,IAAI,CAClC;EAEF,MAAM,cAAc,GAAG,UAAU;EACjC,MAAM,KAAK,QAAQ,GAAG,mBACpB,aACA,wBAAwB,iBAAiB,CAC3C;EACA,IAAI;GACF,MAAM,SAAS,WAAW,aAAa,WAAW,EAAE;GAIpD,MAAM,WAAW,YACb,sBAAsB,aAAa,SAAS,EAAE,qCAC9C;GACJ,MAAM,KAAK,QAAQ,KAAK,MACtB,2BAA2B,WAAW,SAAS,EAAE,+BACnB,SAAS,gBAAgB,QACzD;EACF,UAAU;GACR,MAAM,KAAK,QAAQ,GAAG,SAAS,WAAW,EAAE,YAAY,KAAA,CAAS;EACnE;CACF;;;;;;;;;;;;;;;CAgBA,MAAc,kBACZ,MACA,SACA,gBACwB;EACxB,MAAM,WAAW,QAAQ,WAAW,KAAK;EACzC,IAAI,UAAU,OAAO;EACrB,IAAI,QAAQ,WAAW,cACrB,OAAO,KAAK,mBAAmB,MAAM,cAAc;EAErD,OAAO,KAAK,eACV,SAAS,QAAQ,QAAQ,IAAI,GAC7B,MAAM,KAAK,QAAQ,SAAS,IAAI,CAClC;CACF;;;;;;;;;;;;;;CAeA,MAAc,mBACZ,MACA,gBACwB;EACxB,IAAI;GAGF,MAAM,YADM,MADS,KAAK,QAAQ,KAAK,MAAM,mBAAmB,IAAI,CAAC,GAClD,QAAQ,EAAE,KACN;GACvB,OAAO,oBACL,OAAO,aAAa,WAAW,WAAW,MAC1C,gBACA,cACF;EACF,QAAQ;GACN,OAAO;EACT;CACF;;;;;;;;;;;;;;;;;CAkBA,MAAc,eACZ,MACA,SAAwB,MACA;EACxB,IAAI;GAEF,MAAM,OAAM,MADS,KAAK,QAAQ,KAAK,MAAM,mBAAmB,IAAI,CAAC,GAClD,QAAQ,EAAE;GAG7B,IAAI,KAAK;IACP,MAAM,WACJ,OAAO,IAAI,cAAc,WAAW,IAAI,UAAU,KAAK,IAAI;IAC7D,MAAM,WACJ,IAAI,aAAa,OAAO,OAAO,IAAI,SAAS,EAAE,KAAK,IAAI;IACzD,IAAI,YAAY,UAAU;KACxB,MAAM,MAAM,GAAG,SAAS,YAAY,EAAE,GAAG;KACzC,OAAO,eAAe,GAAG,IAAI,OAAO;IACtC;IACA,MAAM,MAAM,OAAO,IAAI,QAAQ,WAAW,IAAI,IAAI,KAAK,IAAI;IAC3D,IAAI,KAAK,OAAO;GAClB;GAEA,OAAO,QAAQ,KAAK,KAAK;EAC3B,QAAQ;GAIN,OAAO,QAAQ,KAAK,KAAK;EAC3B;CACF;;;;;;CAOA,MAAc,iBACZ,SACwB;EACxB,IAAI,QAAQ,WAAW,eAAe,CAAC,QAAQ,gBAAgB,QAC7D,OAAO;EAET,MAAM,MAAM,QAAQ,eAAe,MAAM,SACvC,KAAK,KAAK,YAAY,EAAE,SAAS,MAAM,CACzC;EACA,IAAI,CAAC,KAAK,OAAO;EAEjB,QADc,MAAM,IAAI,KAAK,GAAG,KACzB,KAAQ;CACjB;;;;;;CAOA,MAAc,QACZ,SACA,MACwB;EACxB,OACG,MAAM,KAAK,iBAAiB,OAAO,KACpC,KAAK,cAAc,IAAI,IAAI,KAC3B;CAEJ;;;;;;;;;CAUA,MAAc,kBACZ,WACA,MACA,SACwB;EACxB,MAAM,SAAS,UAAU,QAAQ,QAAQ,MAAM,QAAQ,WAAW;EAClE,MAAM,UAAU,MAAM,KAAK,gBAAgB,MAAM;EACjD,MAAM,iBAAiB,MAAM,KAAK,sBAAsB,QAAQ,OAAO;EACvE,IAAI,CAAC,gBACH,MAAM,IAAI,MAAM,+CAA+C;EAEjE,MAAM,YAAY,MAAM,KAAK,kBAC3B,MACA,SACA,eAAe,IACjB;EACA,MAAM,KAAK,QAAQ,KAAK,MACtB,0BAA0B,WAAW,QAAQ,gBAAgB,SAAS,CACxE;EACA,OAAO;CACT;CAEA,MAAc,sBACZ,QACA,SAC6C;EAC7C,MAAM,iBAAiB,qBAAqB,OAAO;EACnD,IAAI,CAAC,gBAAgB,6BAA6B,OAAO;EACzD,MAAM,aAAa,eAAe,qBAAqB,SACnD,eAAe,sBACf,CAAC,eAAe,IAAI;EACxB,KAAK,MAAM,QAAQ,YACjB,IAAI,MAAM,KAAK,yBAAyB,QAAQ,IAAI,GAClD,OAAO;GAAE;GAAM,UAAU,eAAe;EAAS;CAIvD;CAEA,MAAc,yBACZ,QACA,QACkB;EAClB,MAAM,YAAY,WAAW,MAAM;EACnC,MAAM,eAAe,WAAW,wCAAwC;EAOxE,MAAM,OAAM,MANS,KAAK,QAAQ,KAAK,MACrC,yEAC0C,aAAa,mCACrC,UAAU,MAAM,aAAa,QAAQ,OAAO,SACnD,UAAU,iCACvB,GACmB,QAAQ,EAAE,MAAM,CAAC;EACpC,MAAM,cAAc,gBAAgB,IAAI,YAAY;EACpD,MAAM,aAAa,gBAAgB,IAAI,WAAW;EAClD,OAAO,cAAc,KAAK,gBAAgB;CAC5C;;;;;;;;CASA,MAAc,oBACZ,QACA,QACA,WACA,SACA,MACkB;EAClB,IAAI,OAAO,WAAW,YAAY,EAAE,kBAAkB,OAAO,OAAO;EACpE,IAAI,QAAQ,WAAW,gBAAgB,QAAQ,WAAW,OACxD,OAAO;EAET,MAAM,YAAY,IAAI,gBAAgB,MAAM;EAC5C,IAAI;GACF,MAAM,KAAK,aAAa,WAAW,WAAW,OAAO;GACrD,KAAK,YAAY;GACjB,OAAO;EACT,QAAQ;GACN,IAAI,gBAAgB,SAAS;GAC7B,OAAO;EACT;CACF;;;;CAKA,MAAc,gBAAgB,QAAuC;EAInE,QAAO,MAHc,KAAK,QAAQ,KAAK,MACrC,yBAAyB,MAAM,CACjC,GACc,QAAQ,EAAE,KAAK,SAAS;GACpC,MAAM,OAAO,IAAI,WAAW;GAC5B,MAAM,OAAO,IAAI,WAAW;EAC9B,EAAE;CACJ;;;;CAKA,MAAc,eAAe,WAA0C;EACrE,OAAO,KAAK,gBAAgB,WAAW,SAAS,CAAC;CACnD;;;;CAKA,MAAc,WACZ,WACA,MACwD;EAGxD,MAAM,aACJ,KAAK,YAAY,KAAK,aAClB,iBAAiB,WAAW,KAAK,UAAU,IAC3C,aAAa,SAAS;EAE5B,MAAM,OAAM,MADgB,KAAK,QAAQ,KAAK,MAAM,UAAU,GACpC,QAAQ,EAAE,MAAM,CAAC;EAC3C,MAAM,eAAe,OAAO,IAAI,iBAAiB,CAAC;EAElD,IAAI;EACJ,MAAM,SAAS;GAAC,IAAI;GAAM,IAAI;GAAM,IAAI;GAAM,IAAI;EAAI,EAAE,KAAK,MAC3D,OAAO,CAAC,CACV;EACA,IAAI,OAAO,OAAO,MAAM,OAAO,SAAS,CAAC,CAAC,GACxC,OAAO;EAGT,IAAI,eAAiC;EACrC,MAAM,WAAW,KAAK,WAClB,0BAA0B,SAAS,IACnC,mBAAmB,SAAS;EAChC,MAAM,cAAc,MAAM,KAAK,QAAQ,KAAK,MAAM,QAAQ;EAC1D,KAAK,MAAM,WAAW,YAAY,QAAQ,GACxC,eAAe,sBACb,iBAAiB,YAAY,KAAA,IAAY,cACzC,qBAAqB,OAAO,QAAQ,aAAa,CAAC,CACpD;EAGF,OAAO;GAAE;GAAc;GAAM;EAAa;CAC5C;CAEA,cAAsB,WAA8B;EAClD,MAAM,OAAO,KAAK,QAAQ,IAAI,SAAS;EACvC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,kBAAkB,WAAW;EAE/C,OAAO;CACT;AACF;;;;;;;AAQA,eAAsB,aACpB,SACkB;CAClB,MAAM,SAAS,MAAM,WACnB,SAAS,YACT,SAAS,SACT,SAAS,oBACX;CACA,SAAS,aAAa,UAAU,OAAO,QAAQ,OAAO;CACtD,OAAO,IAAI,aAAa,QAAQ,SAAS,YAAY;AACvD;;;ACxvCA,SAAS,SACP,OACA,OACA,UACa;CACb,MAAM,MAAM,GAAG,SAAS,0BAA0B;CAClD,MAAM,OAAO,GAAG,QAAQ,4BAA4B;CACpD,KAAK,cAAc;CACnB,MAAM,QAAQ,GAAG,SAAS,sBAAsB;CAChD,MAAM,OAAO;CACb,MAAM,QAAQ;CACd,MAAM,iBAAiB,eAAe,SAAS,MAAM,KAAK,CAAC;CAC3D,IAAI,YAAY,IAAI;CACpB,IAAI,YAAY,KAAK;CACrB,OAAO;AACT;AAEA,SAAS,UACP,OACA,OACA,MACA,UACa;CACb,MAAM,MAAM,GAAG,SAAS,0BAA0B;CAClD,MAAM,OAAO,GAAG,QAAQ,4BAA4B;CACpD,KAAK,cAAc;CACnB,MAAM,QAAQ,GAAG,SAAS,sBAAsB;CAChD,MAAM,OAAO;CACb,MAAM,MAAM,OAAO,KAAK,GAAG;CAC3B,MAAM,MAAM,OAAO,KAAK,GAAG;CAC3B,MAAM,OAAO,OAAO,KAAK,IAAI;CAC7B,MAAM,QAAQ,OAAO,KAAK;CAC1B,MAAM,UAAU,GAAG,QAAQ,4BAA4B;CACvD,QAAQ,cAAc,OAAO,KAAK;CAClC,MAAM,iBAAiB,eAAe;EACpC,QAAQ,cAAc,MAAM;EAC5B,SAAS,OAAO,MAAM,KAAK,CAAC;CAC9B,CAAC;CACD,IAAI,YAAY,IAAI;CACpB,IAAI,YAAY,KAAK;CACrB,IAAI,YAAY,OAAO;CACvB,OAAO;AACT;;;;;;;;;AAUA,SAAgB,kBACd,OACA,SACA,WACa;CACb,MAAM,SAAS,GAAG,OAAO,6BAA6B;CACtD,MAAM,EAAE,OAAO,iBAAiB;CAChC,MAAM,WAAW,iBAAiB,aAAa,iBAAiB,WAAW,iBAAiB;CAC5F,MAAM,WAAW,iBAAiB;CAClC,MAAM,aAAa,iBAAiB,WAAW,iBAAiB,WAAW,iBAAiB;CAE5F,IAAI,UAAU;EACZ,OAAO,YAAY,SAAS,QAAQ,MAAM,YAAY,cAAc,UAAU,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;EACrG,OAAO,YACL,UAAU,WAAW,MAAM,aAAa;GAAE,KAAK;GAAG,KAAK;GAAG,MAAM;EAAK,IAAI,gBACvE,UAAU,QAAQ,EAAE,YAAY,CAAC,CACnC,CACF;CACF;CACA,IAAI,UAAU;EACZ,OAAO,YAAY,SAAS,QAAQ,MAAM,YAAY,cAAc,UAAU,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;EACrG,OAAO,YACL,UAAU,SAAS,MAAM,WAAW;GAAE,KAAK;GAAG,KAAK;GAAI,MAAM;EAAI,IAAI,cACnE,UAAU,QAAQ,EAAE,UAAU,CAAC,CACjC,CACF;CACF;CACA,IAAI,YAAY;EACd,OAAO,YACL,SAAS,UAAU,MAAM,cAAc,gBAAgB,UAAU,QAAQ,EAAE,YAAY,CAAC,CAAC,CAC3F;EACA,OAAO,YACL,UAAU,UAAU,MAAM,cAAc;GAAE,KAAK;GAAG,KAAK;GAAI,MAAM;EAAE,IAAI,iBACrE,UAAU,QAAQ,EAAE,aAAa,CAAC,CACpC,CACF;CACF;CAGA,MAAM,UAAU,GAAG,SAAS,0BAA0B;CACtD,MAAM,YAAY,GAAG,QAAQ,4BAA4B;CACzD,UAAU,cAAc;CACxB,MAAM,SAAS,GAAG,UAAU,uBAAuB;CACnD,KAAK,MAAM,QAAQ;EAAC;EAAQ;EAAW;CAAO,GAAY;EACxD,MAAM,SAAS,GAAG,QAAQ;EAC1B,OAAO,QAAQ;EACf,OAAO,cAAc,SAAS,YAAY,YAAY,SAAS,UAAU,UAAU;EACnF,IAAI,SAAS,MAAM,YAAY,OAAO,WAAW;EACjD,OAAO,YAAY,MAAM;CAC3B;CACA,OAAO,iBAAiB,gBAAgB;EACtC,UAAU,aAAa,OAAO,KAAqC;CACrE,CAAC;CACD,QAAQ,YAAY,SAAS;CAC7B,QAAQ,YAAY,MAAM;CAC1B,OAAO,YAAY,OAAO;CAG1B,MAAM,YAAY,GAAG,SAAS,0BAA0B;CACxD,MAAM,cAAc,GAAG,QAAQ,4BAA4B;CAC3D,YAAY,cAAc;CAC1B,MAAM,cAAc,GAAG,SAAS,yBAAyB;CACzD,YAAY,OAAO;CACnB,YAAY,UAAU,MAAM;CAC5B,YAAY,iBAAiB,gBAAgB,UAAU,SAAS,YAAY,OAAO,CAAC;CACpF,UAAU,YAAY,WAAW;CACjC,UAAU,YAAY,WAAW;CACjC,OAAO,YAAY,SAAS;CAG5B,MAAM,YAAY,GAAG,SAAS,0BAA0B;CACxD,MAAM,cAAc,GAAG,QAAQ,4BAA4B;CAC3D,YAAY,cAAc;CAC1B,MAAM,eAAe,GAAG,UAAU,uBAAuB;CACzD,MAAM,YAAY,GAAG,QAAQ;CAC7B,UAAU,QAAQ;CAClB,UAAU,cAAc;CACxB,aAAa,YAAY,SAAS;CAClC,KAAK,MAAM,UAAU,QAAQ,eAAe;EAC1C,MAAM,SAAS,GAAG,QAAQ;EAC1B,OAAO,QAAQ;EACf,OAAO,cAAc;EACrB,IAAI,WAAW,MAAM,UAAU,OAAO,WAAW;EACjD,aAAa,YAAY,MAAM;CACjC;CACA,aAAa,iBAAiB,gBAC5B,UAAU,WAAW,aAAa,SAAS,KAAA,CAAS,CACtD;CACA,UAAU,YAAY,WAAW;CACjC,UAAU,YAAY,YAAY;CAClC,OAAO,YAAY,SAAS;CAE5B,OAAO;AACT;;;ACvJA,SAAS,WAAW,OAAe,OAAe,SAAwC;CACxF,MAAM,SAAS,GAAG,UAAU,2BAA2B;EAAE,MAAM;EAAU;CAAM,CAAC;CAChF,OAAO,aAAa,cAAc,KAAK;CACvC,OAAO,YAAY,QAAQ,KAAK,CAAC;CACjC,OAAO,iBAAiB,UAAU,MAAM;EACtC,EAAE,gBAAgB;EAClB,QAAQ;CACV,CAAC;CACD,OAAO;AACT;AAEA,SAAS,YAAY,OAAuB;CAC1C,IAAI,SAAS,KAAW,OAAO,IAAI,QAAQ,KAAW,QAAQ,CAAC,EAAE;CACjE,IAAI,SAAS,KAAO,OAAO,IAAI,QAAQ,KAAO,QAAQ,CAAC,EAAE;CACzD,OAAO,OAAO,KAAK;AACrB;;;;;;;;;;AAWA,SAAgB,oBACd,OACA,UACA,SACA,WACa;CACb,MAAM,OAAO,GAAG,OAAO,2BAA2B;CAClD,KAAK,QAAQ,UAAU,MAAM;CAE7B,MAAM,MAAM,GAAG,OAAO,0BAA0B;CAGhD,IAAI,YACF,WACE,MAAM,UAAU,eAAe,cAC/B,MAAM,UAAU,MAAM,MAAM,MAAM,cAC5B,UAAU,mBAAmB,MAAM,IAAI,CAAC,MAAM,OAAO,CAC7D,CACF;CAGA,MAAM,WAAW,GAAG,OAAO,gCAAgC;CAC3D,MAAM,OAAO,GAAG,OAAO,6BAA6B,EAAE,OAAO,MAAM,KAAK,CAAC;CACzE,KAAK,cAAc,MAAM;CACzB,MAAM,OAAO,GAAG,OAAO,2BAA2B;CAClD,MAAM,QAAkB,CAAC,MAAM,MAAM;CACrC,IAAI,MAAM,iBAAiB,KAAA,GAAW,MAAM,KAAK,GAAG,YAAY,MAAM,YAAY,EAAE,IAAI;CACxF,MAAM,KAAK,MAAM,eAAe,UAAU,UAAU,SAAS;CAC7D,IAAI,MAAM,eAAe,UAAU,MAAM,KAAK,QAAQ;CACtD,KAAK,cAAc,MAAM,KAAK,KAAK;CACnC,SAAS,YAAY,IAAI;CACzB,SAAS,YAAY,IAAI;CACzB,SAAS,iBAAiB,eAAe,UAAU,eAAe,MAAM,EAAE,CAAC;CAC3E,IAAI,YAAY,QAAQ;CAGxB,MAAM,UAAU,GAAG,OAAO,8BAA8B;CACxD,QAAQ,YAAY,WAAW,iBAAiB,MAAM,YAAY,UAAU,OAAO,MAAM,EAAE,CAAC,CAAC;CAC7F,QAAQ,YACN,WAAW,eAAe,MAAM,eAAe,UAAU,eAAe,MAAM,EAAE,CAAC,CACnF;CACA,QAAQ,YAAY,WAAW,gBAAgB,MAAM,aAAa,UAAU,SAAS,MAAM,EAAE,CAAC,CAAC;CAC/F,IAAI,YAAY,OAAO;CAEvB,KAAK,YAAY,GAAG;CAEpB,IAAI,UACF,KAAK,YACH,kBAAkB,OAAO,SAAS;EAChC,UAAU,UAAU,UAAU,QAAQ,MAAM,IAAI,KAAK;EACrD,eAAe,SAAS,UAAU,aAAa,MAAM,IAAI,IAAI;EAC7D,WAAW,YAAY,UAAU,SAAS,MAAM,IAAI,OAAO;EAC3D,aAAa,aAAa,UAAU,WAAW,MAAM,IAAI,QAAQ;CACnE,CAAC,CACH;CAGF,OAAO;AACT;;;;;;;;;;ACjCA,SAAgB,cAAc,SAAqC;CACjE,MAAM,EAAE,WAAW,SAAS,eAAe;CAC3C,MAAM,kCAAkB,IAAI,IAAY;CACxC,IAAI,sBAAsB;CAC1B,IAAI,iBAA6C;CAEjD,UAAU,YAAY;CAGtB,MAAM,WAAW,GAAG,OAAO,yBAAyB;CACpD,SAAS,YAAY,QAAQ,MAAM,QAAQ,EAAE,CAAC;CAC9C,MAAM,WAAW,GAAG,MAAM;CAC1B,SAAS,cAAc;CACvB,SAAS,YAAY,QAAQ;CAK7B,MAAM,YAAY,GAAG,OAAO;CAC5B,UAAU,OAAO;CACjB,UAAU,WAAW;CACrB,UAAU,MAAM,UAAU;CAK1B,SAAS,iBAAiB,eAAe;EACvC,IAAI,YACF,YAAiB;OAEjB,UAAU,MAAM;CAEpB,CAAC;CACD,SAAS,iBAAiB,aAAa,MAAM;EAC3C,EAAE,eAAe;EACjB,SAAS,UAAU,IAAI,UAAU;CACnC,CAAC;CACD,SAAS,iBAAiB,mBAAmB,SAAS,UAAU,OAAO,UAAU,CAAC;CAClF,SAAS,iBAAiB,SAAS,MAAM;EACvC,EAAE,eAAe;EACjB,SAAS,UAAU,OAAO,UAAU;EACpC,MAAM,QAAQ,EAAE,cAAc;EAC9B,IAAI,OAAO,UAAU,KAAK;CAC5B,CAAC;CACD,UAAU,iBAAiB,gBAAgB;EACzC,IAAI,UAAU,OAAO,UAAU,UAAU,KAAK;EAC9C,UAAU,QAAQ;CACpB,CAAC;CAGD,MAAM,SAAS,GAAG,OAAO,4CAA4C;CACrE,MAAM,WAAW,GAAG,SAAS,sBAAsB;CACnD,SAAS,OAAO;CAChB,SAAS,cAAc,QAAQ,kBAAkB;CACjD,IAAI,QAAQ,YAAY,SAAS,QAAQ,QAAQ;CACjD,MAAM,YAAY,GAAG,UAAU,yBAAyB,EAAE,MAAM,SAAS,CAAC;CAC1E,UAAU,cAAc;CACxB,MAAM,gBAAgB;EACpB,MAAM,MAAM,SAAS,MAAM,KAAK;EAChC,IAAI,CAAC,KAAK;EACV,MAAM,aACJ,kBAAkB,eAAe,QAAQ,MAAM,iBAAiB;EAClE,QAAa,QAAQ,KAAK,aAAa,kBAAkB,UAAU,IAAI,YAAY,CAAC,EAAE,WAC9E;GACJ,SAAS,QAAQ;GACjB,iBAAiB;EACnB,SACM,CAEN,CACF;CACF;CACA,UAAU,iBAAiB,SAAS,OAAO;CAC3C,SAAS,iBAAiB,YAAY,MAAM;EAC1C,IAAI,EAAE,QAAQ,SAAS,QAAQ;CACjC,CAAC;CACD,SAAS,iBAAiB,eAAe;EACvC,IAAI,kBAAkB,SAAS,MAAM,KAAK,MAAM,eAAe,KAC7D,iBAAiB;CAErB,CAAC;CACD,OAAO,YAAY,QAAQ;CAC3B,OAAO,YAAY,SAAS;CAS5B,MAAM,UAAU,QAAQ,cAAc,CAAC;CACvC,MAAM,YAAY,GAAG,OAAO,2BAA2B;CACvD,IAAI,yBAA+D;CACnE,IAAI,QAAQ,SAAS,GAAG;EACtB,MAAM,UAAU,GAAG,UAAU,iCAAiC;GAC5D,MAAM;GACN,iBAAiB;GACjB,iBAAiB;EACnB,CAAC;EACD,MAAM,eAAe,GAAG,QAAQ,qCAAqC;EACrE,aAAa,cAAc,QAAQ,mBAAmB;EACtD,QAAQ,YAAY,YAAY;EAChC,QAAQ,YAAY,QAAQ,MAAM,aAAa,EAAE,CAAC;EAElD,MAAM,OAAO,GAAG,OAAO,8BAA8B,EAAE,MAAM,UAAU,CAAC;EACxE,KAAK,SAAS;EAEd,IAAI,WAAW;EACf,MAAM,eAAe,SAAwB;GAC3C,WAAW;GACX,KAAK,SAAS,CAAC;GACf,QAAQ,aAAa,iBAAiB,OAAO,IAAI,CAAC;GAClD,QAAQ,UAAU,OAAO,QAAQ,IAAI;GACrC,IAAI,MAAM,KAAM,mBAA0C,MAAM;EAClE;EAEA,KAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,SAAS,GAAG,UAAU,gCAAgC;IAC1D,MAAM;IACN,MAAM;IACN,OAAO,OAAO;GAChB,CAAC;GACD,OAAO,cAAc,OAAO;GAC5B,OAAO,iBAAiB,eAAe;IACrC,YAAY,KAAK;IACjB,QAAQ,MAAM;IAEd,SAAS,QAAQ,OAAO;IACxB,iBAAiB;GACnB,CAAC;GACD,KAAK,YAAY,MAAM;EACzB;EAEA,QAAQ,iBAAiB,eAAe,YAAY,CAAC,QAAQ,CAAC;EAC9D,UAAU,iBAAiB,YAAY,UAAU;GAC/C,IAAK,MAAwB,QAAQ,YAAY,UAAU;IACzD,YAAY,KAAK;IACjB,QAAQ,MAAM;GAChB;EACF,CAAC;EAGD,0BAA0B,UAAsB;GAC9C,IAAI,CAAC,UAAU,SAAS,MAAM,MAAc,GAAG,YAAY,KAAK;EAClE;EACA,SAAS,iBAAiB,eAAe,sBAAsB;EAE/D,UAAU,YAAY,OAAO;EAC7B,UAAU,YAAY,IAAI;CAC5B;CAKA,MAAM,YAAY,GAAG,SAAS,6BAA6B,EACzD,OACE,iJAEJ,CAAC;CACD,MAAM,cAAc,GAAG,SAAS,yBAAyB;CACzD,YAAY,OAAO;CACnB,MAAM,aAAa,GAAG,MAAM;CAC5B,WAAW,cAAc;CACzB,UAAU,YAAY,WAAW;CACjC,UAAU,YAAY,UAAU;CAMhC,MAAM,iBAAiB,GAAG,SAAS,sBAAsB;CACzD,eAAe,OAAO;CACtB,eAAe,cAAc;CAC7B,eAAe,aAAa,cAAc,qBAAqB;CAG/D,MAAM,SAAS,GAAG,OAAO,uBAAuB;CAChD,OAAO,MAAM,UAAU;CAEvB,SAAS,UAAU,SAAwB,UAAU,OAAa;EAChE,IAAI,CAAC,SAAS;GACZ,OAAO,MAAM,UAAU;GACvB,OAAO,cAAc;GACrB,qBAAqB;GACrB;EACF;EACA,OAAO,MAAM,UAAU;EACvB,OAAO,cAAc;EACrB,OAAO,UAAU,OAAO,SAAS,OAAO;EACxC,qBAAqB;CACvB;CAGA,MAAM,YAAY,GAAG,OAAO,8BAA8B;CAC1D,UAAU,cAAc;CACxB,MAAM,OAAO,GAAG,OAAO,2BAA2B;CAClD,MAAM,QAAQ,GAAG,OAAO,sBAAsB;CAC9C,MAAM,cAAc;CAEpB,SAAS,aAAmB;EAC1B,MAAM,SAAS,QAAQ,UAAU;EACjC,KAAK,YAAY;EACjB,IAAI,OAAO,WAAW,GAAG;GACvB,KAAK,YAAY,KAAK;GACtB,qBAAqB;GACrB;EACF;EAEA,MAAM,cAAc,IAAI,IAAI,OAAO,SAAS,UAAU,MAAM,QAAQ,CAAC;EACrE,MAAM,iBAAiB,QAAQ,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC,GAC7D,KAAK,aAAa,SAAS,EAAE,EAC7B,QAAQ,eAAe,CAAC,YAAY,IAAI,UAAU,CAAC;EACtD,KAAK,MAAM,SAAS,QAClB,KAAK,YACH,oBAAoB,OAAO,gBAAgB,IAAI,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG;GAC3E,qBAAqB,IAAI,YAAY,QAAQ,mBAAmB,IAAI,OAAO;GAC3E,SAAS,OAAO,QAAQ,YAAY,EAAE;GACtC,WAAW,OAAO;IAChB,gBAAgB,OAAO,EAAE;IACzB,QAAQ,YAAY,EAAE;GACxB;GACA,UAAU,IAAI,UAAU;IAEtB,sBAAsB;IACtB,IAAI;KACF,QAAQ,cAAc,IAAI,KAAK;IACjC,UAAU;KACR,sBAAsB;IACxB;GACF;GACA,eAAe,IAAI,SAAS;IAC1B,QAAa,cAAc,IAAI,IAAI,EAAE,YAAY,CAEjD,CAAC;GACH;GACA,WAAW,IAAI,YAAY,QAAQ,eAAe,IAAI,OAAO;GAC7D,aAAa,IAAI,aAAa,QAAQ,iBAAiB,IAAI,QAAQ;GACnE,iBAAiB,OAAO;IACtB,IAAI,gBAAgB,IAAI,EAAE,GACxB,gBAAgB,OAAO,EAAE;SAEzB,gBAAgB,IAAI,EAAE;IAExB,WAAW;GACb;EACF,CAAC,CACH;EAEF,qBAAqB;CACvB;CAMA,SAAS,uBAA6B;EACpC,UAAU,UAAU,OAClB,gCACA,UAAU,eAAe,UAAU,YACrC;CACF;CAEA,SAAS,cAAkC;EAGzC,MAAM,YAAY,eAAe,MAAM,KAAK;EAC5C,OAAO;GACL,YAAY,YAAY,UAAU,WAAW;GAC7C,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACnC;CACF;CAEA,SAAS,kBAAkB,QAAiD;EAC1E,MAAM,gBAAoC;GACxC,GAAG,YAAY;GACf,GAAI,OAAO,aAAa,EAAE,YAAY,OAAO,WAAW,IAAI,CAAC;EAC/D;EACA,IAAI,OAAO,MAAM,cAAc,OAAO,OAAO;EAC7C,IAAI,OAAO,YAAY,cAAc,aAAa,OAAO;EACzD,OAAO;CACT;CAEA,SAAS,UAAU,OAAuB;EAIxC,KAAK,MAAM,EAAE,MAAM,gBAAgB,yBAAyB,MAAM,KAAK,KAAK,CAAC,GAAG;GAC9E,MAAM,UACJ,WAAW,SAAS,IAChB;IAAE,GAAG,YAAY;IAAG,gBAAgB;GAAW,IAC/C,YAAY;GAClB,QAAa,QAAQ,MAAM,OAAO,EAAE,YAAY,CAEhD,CAAC;EACH;CACF;CAMA,eAAe,cAA6B;EAC1C,IAAI;EACJ,IAAI;GACF,aAAa,MAAM,aAAa;EAClC,SAAS,OAAO;GACd,UAAU,iBAAiB,QAAQ,MAAM,UAAU,wBAAwB,IAAI;GAC/E;EACF;EACA,IAAI,CAAC,cAAc,WAAW,WAAW,GAAG;EAC5C,eAAe,UAAU;CAC3B;CAEA,SAAS,eAAe,YAAyC;EAG/D,MAAM,QAAQ,WAAW,KAAK,cAAc,UAAU,IAAI;EAC1D,MAAM,aAAa,IAAI,IACrB,WAAW,KAAK,cAAc,CAAC,UAAU,MAAM,UAAU,UAAU,CAAC,CACtE;EACA,MAAM,aAAa,IAAI,IACrB,WAAW,KAAK,cAAc,CAAC,UAAU,MAAM,UAAU,IAAI,CAAC,CAChE;EACA,MAAM,cAAc,MAAM,QAAQ,SAAuB,gBAAgB,IAAI;EAC7E,MAAM,cAAc,MAAM,QAAQ,SAAS,EAAE,gBAAgB,KAAK;EAElE,KAAK,MAAM,EAAE,MAAM,gBAAgB,yBAAyB,WAAW,GAAG;GACxE,MAAM,UAA8B;IAClC,GAAG,YAAY;IACf,GAAI,WAAW,SAAS,IAAI,EAAE,gBAAgB,WAAW,IAAI,CAAC;IAC9D,GAAI,WAAW,IAAI,IAAI,IAAI,EAAE,YAAY,WAAW,IAAI,IAAI,EAAE,IAAI,CAAC;IACnE,GAAI,WAAW,IAAI,IAAI,IAAI,EAAE,MAAM,WAAW,IAAI,IAAI,EAAE,IAAI,CAAC;GAC/D;GACA,QAAa,QAAQ,MAAM,OAAO,EAAE,YAAY,CAEhD,CAAC;EACH;EACA,KAAK,MAAM,QAAQ,aAAa;GAC9B,MAAM,UAA8B;IAClC,GAAG,YAAY;IACf,GAAI,WAAW,IAAI,IAAI,IAAI,EAAE,YAAY,WAAW,IAAI,IAAI,EAAE,IAAI,CAAC;IACnE,GAAI,WAAW,IAAI,IAAI,IAAI,EAAE,MAAM,WAAW,IAAI,IAAI,EAAE,IAAI,CAAC;GAC/D;GACA,QAAa,QAAQ,MAAM,OAAO,EAAE,YAAY,CAEhD,CAAC;EACH;CACF;CAGA,MAAM,aAAwC,MAAM,UAAU,EAAE,WAAW,YAAY;CACvF,MAAM,WAAsC,MAC1C,UAAU,EAAE,OAAO,WAAW,kBAAkB,IAAI;CACtD,MAAM,sBAAiD;EACrD,UAAU,IAAI;EACd,IAAI,CAAC,qBAAqB,WAAW;CACvC;CAEA,QAAQ,GAAG,WAAW,SAAS;CAC/B,QAAQ,GAAG,SAAS,OAAO;CAC3B,QAAQ,GAAG,cAAc,aAAa;CACtC,QAAQ,GAAG,gBAAgB,aAAa;CACxC,QAAQ,GAAG,gBAAgB,aAAa;CAExC,UAAU,YAAY,QAAQ;CAC9B,UAAU,YAAY,SAAS;CAC/B,UAAU,YAAY,MAAM;CAC5B,IAAI,QAAQ,SAAS,GAAG,UAAU,YAAY,SAAS;CACvD,UAAU,YAAY,SAAS;CAC/B,UAAU,YAAY,cAAc;CACpC,UAAU,YAAY,MAAM;CAC5B,UAAU,YAAY,GAAG,OAAO,wBAAwB,CAAC;CACzD,UAAU,YAAY,SAAS;CAC/B,UAAU,YAAY,IAAI;CAE1B,WAAW;CAKX,MAAM,iBACJ,OAAO,mBAAmB,cACtB,IAAI,qBAAqB,qBAAqB,CAAC,IAC/C;CACN,gBAAgB,QAAQ,SAAS;CAKjC,IAAI,QAAQ,YAAY,SAAS,OAAO,QAAQ;CAEhD,aAAa;EACX,QAAQ,IAAI,WAAW,SAAS;EAChC,QAAQ,IAAI,SAAS,OAAO;EAC5B,QAAQ,IAAI,cAAc,aAAa;EACvC,QAAQ,IAAI,gBAAgB,aAAa;EACzC,QAAQ,IAAI,gBAAgB,aAAa;EACzC,gBAAgB,WAAW;EAC3B,IAAI,wBACF,SAAS,oBAAoB,eAAe,sBAAsB;EAEpE,UAAU,YAAY;CACxB;AACF;;;;;;ACpcA,IAAM,kBAEF;CACF,WAAW;CACX,UAAU;CACV,OAAO;CACP,YAAY;CACZ,WAAW;AACb;;;;;;;;;;;;;;;;;;AAwBA,IAAa,gBAAb,MAA+C;CAC7C;CACA;CACA;CACA;CACA;CACA;CACA;CACA,iBAA2C,IAAI,WAAW,IAAI;CAC9D;CACA;CACA;CACA,oBAAiD;CACjD,uBAA8C,QAAQ,QAAQ;CAC9D,WAAmB;CAGnB,iBAA8C;CAC9C,oBAAiD;CACjD,uBAAiE;CAIjE,aAAoC;CACpC,cAAqC;CAErC,qBAAkD;;;;;;CAOlD,YAAY,SAAyC;EACnD,KAAK,WAAW;GAAE,GAAG;GAAiB,GAAG;EAAQ;EACjD,KAAK,SAAS;GACZ,WAAW,KAAK,SAAS;GACzB,YAAY,KAAK,SAAS;GAC1B,QAAQ,CAAC;GACT,MAAM,CAAC;EACT;CACF;;;;;;;;CASA,MAAM,KAA+B;EACnC,KAAK,WAAW;EAChB,KAAK,OAAO;EACZ,KAAK,gBAAgB,IAAI,aAAa;EACtC,KAAK,aAAa,KAAK,iBAAiB;EACxC,KAAK,SAAS,KAAK,aAAa;EAEhC,KAAK,gBAAgB,IAAI,aAAa;GACpC;GACA,SAAS,KAAK;GACd,OAAO,MAAM,UAAU,KAAK,MAAM,MAAM,KAAK;GAC7C,iBAAiB,KAAK,WAAW;EACnC,CAAC;EACD,KAAK,0BAA0B;GAC7B,KAAK,uBAAuB,KAAK,qBAAqB,KAAK,YAAY;IACrE,IAAI,KAAK,UAAU;IACnB,IAAI;KACF,MAAM,KAAK,eAAe,8BAA8B;IAC1D,SAAS,OAAgB;KACvB,MAAM,aAAa,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;KAC3E,KAAK,MAAM,SAAS,EAAE,OAAO,WAAW,CAAC;IAC3C;GACF,CAAC;EACH;EACA,IAAI,GAAG,cAAc,KAAK,iBAAiB;EAG3C,KAAK,cAAc,YAAY,KAAK,MAAM;EAG1C,IAAI,KAAK,UACP,KAAK,kBAAkB,cAAc;GACnC,WAAW,KAAK;GAChB,SAAS;GACT,gBAAgB,KAAK,SAAS;GAC9B,YAAY,KAAK,SAAS;GAC1B,UAAU,KAAK,SAAS;GACxB,YAAY,KAAK,SAAS;GAC1B,iBAAiB,KAAK,SAAS;GAC/B,YAAY,KAAK,SAAS;EAC5B,CAAC;EAIH,KAAK,qBAAqB;EAG1B,IAAI,CAAC,KAAK,OAAO,WAAW;GAC1B,KAAK,OAAO,UAAU,IAAI,UAAU;GAEpC,4BAA4B;IAC1B,KAAK,qBAAqB;GAC5B,CAAC;EACH;EAEA,OAAO,KAAK;CACd;;;;;CAMA,WAAiB;EACf,KAAK,WAAW;EAEhB,IAAI,KAAK,gBAAgB;GACvB,OAAO,oBAAoB,UAAU,KAAK,cAAc;GACxD,KAAK,iBAAiB;EACxB;EACA,IAAI,KAAK,qBAAqB,KAAK,MAAM;GACvC,KAAK,KAAK,IAAI,UAAU,KAAK,iBAAiB;GAC9C,KAAK,oBAAoB;EAC3B;EACA,IAAI,KAAK,sBAAsB;GAC7B,SAAS,oBAAoB,SAAS,KAAK,oBAAoB;GAC/D,KAAK,uBAAuB;EAC9B;EAEA,KAAK,qBAAqB;EAC1B,IAAI,KAAK,qBAAqB,KAAK,MAAM;GACvC,KAAK,KAAK,IAAI,cAAc,KAAK,iBAAiB;GAClD,KAAK,oBAAoB;EAC3B;EAGA,KAAK,kBAAkB;EACvB,KAAK,kBAAkB,KAAA;EACvB,MAAM,eAAe,KAAK;EAC1B,KAAK,gBAAgB,KAAA;EAGrB,MAAM,gBAAgB,KAAK;EAC3B,KAAK,iBAAiB,KAAA;EACtB,KAAU,qBAAqB,cAAc;GAC3C,cAAc,QAAQ;GACtB,IAAI,eAAe,cAAc,MAAM,WAAW,OAAO,QAAQ,CAAC,EAAE,YAAY,KAAA,CAAS;EAC3F,CAAC;EAGD,KAAK,QAAQ,YAAY,YAAY,KAAK,MAAM;EAGhD,KAAK,YAAY,YAAY,YAAY,KAAK,UAAU;EAExD,KAAK,OAAO,KAAA;EACZ,KAAK,gBAAgB,KAAA;EACrB,KAAK,aAAa,KAAA;EAClB,KAAK,SAAS,KAAA;EACd,KAAK,WAAW,KAAA;EAChB,KAAK,eAAe,MAAM;CAC5B;;;;;;;;CAaA,MAAM,QACJ,QACA,SAC0B;EAC1B,OAAO,KAAK,SAAS,EAAE,QAAQ,QAAQ,OAAO;CAChD;;;;;;CAOA,YAAY,IAAkB;EAC5B,KAAK,eAAe,YAAY,EAAE;CACpC;;;;CAKA,YAAkB;EAChB,KAAK,eAAe,UAAU;CAChC;;;;CAKA,YAA+B;EAC7B,OAAO,KAAK,eAAe,UAAU,KAAK,CAAC;CAC7C;;;;;;CAOA,SAAS,IAAyC;EAChD,OAAO,KAAK,eAAe,SAAS,EAAE;CACxC;;;;;;;;;;CAWA,gBAAgB,IAA+C;EAC7D,OAAO,KAAK,eAAe,gBAAgB,EAAE,KAAK,QAAQ,QAAQ,IAAI;CACxE;;;;;;;;;CAUA,uBAAuB,IAAY,UAA6C;EAC9E,OAAO,KAAK,eAAe,uBAAuB,IAAI,QAAQ,KAAK,QAAQ,QAAQ,IAAI;CACzF;;;;;;;CAQA,mBAAmB,IAAY,SAAwB;EACrD,KAAK,eAAe,mBAAmB,IAAI,OAAO;CACpD;;;;;;CAOA,YAAY,IAAkB;EAC5B,KAAK,eAAe,YAAY,EAAE;CACpC;;;;;;;CAQA,cAAc,IAAY,OAAwC;EAChE,KAAK,eAAe,cAAc,IAAI,KAAK;CAC7C;;;;;;;;CASA,gBAAgB,IAAY,SAAuB;EACjD,KAAK,eAAe,gBAAgB,IAAI,OAAO;CACjD;;;;;;;CAQA,eAAe,IAAY,SAAwB;EACjD,KAAK,eAAe,eAAe,IAAI,OAAO;CAChD;;;;;;;;CASA,iBAAiB,IAAY,UAAyB;EACpD,KAAK,eAAe,iBAAiB,IAAI,QAAQ;CACnD;;;;;;;CAQA,MAAM,cAAc,IAAY,MAAiC;EAC/D,OAAO,KAAK,SAAS,EAAE,cAAc,IAAI,IAAI;CAC/C;;;;;;;;;;CAWA,MAAM,YAAY,IAAkD;EAClE,OAAO,KAAK,eAAe,YAAY,EAAE;CAC3C;;;;;;CAWA,WAAwB;EACtB,OAAO;GACL,GAAG,KAAK;GACR,QAAQ,KAAK,eAAe,UAAU,KAAK,KAAK,OAAO;EACzD;CACF;;;;;;CAOA,SAAS,UAAsC;EAC7C,KAAK,SAAS;GAAE,GAAG,KAAK;GAAQ,GAAG;EAAS;EAC5C,KAAK,MAAM,aAAa;CAC1B;;;;CAKA,SAAe;EACb,KAAK,OAAO,YAAY,CAAC,KAAK,OAAO;EAErC,IAAI,KAAK,QACP,IAAI,KAAK,OAAO,WAAW;GACzB,KAAK,OAAO,UAAU,OAAO,UAAU;GACvC,KAAK,MAAM,UAAU;EACvB,OAAO;GACL,KAAK,OAAO,UAAU,IAAI,UAAU;GACpC,KAAK,qBAAqB;GAC1B,KAAK,MAAM,QAAQ;EACrB;EAGF,KAAK,MAAM,aAAa;CAC1B;;;;CAKA,SAAe;EACb,IAAI,KAAK,OAAO,WACd,KAAK,OAAO;CAEhB;;;;CAKA,WAAiB;EACf,IAAI,CAAC,KAAK,OAAO,WACf,KAAK,OAAO;CAEhB;;;;;;;CAQA,GAAG,OAA2B,SAA0C;EACtE,IAAI,CAAC,KAAK,eAAe,IAAI,KAAK,GAChC,KAAK,eAAe,IAAI,uBAAO,IAAI,IAAI,CAAC;EAE1C,KAAK,eAAe,IAAI,KAAK,EAAG,IAAI,OAAO;CAC7C;;;;;;;CAQA,IAAI,OAA2B,SAA0C;EACvE,KAAK,eAAe,IAAI,KAAK,GAAG,OAAO,OAAO;CAChD;;;;;;CAOA,SAAkC;EAChC,OAAO,KAAK;CACd;;;;;;CAOA,eAAwC;EACtC,OAAO,KAAK;CACd;;;;;;CAOA,oBAA6C;EAC3C,OAAO,KAAK;CACd;;;;;CAMA,WAAiC;EAC/B,IAAI,CAAC,KAAK,eACR,MAAM,IAAI,MAAM,0DAA0D;EAE5E,OAAO,KAAK;CACd;;;;CAKA,aAAuC;EACrC,IAAI,CAAC,KAAK,gBAAgB;GACxB,KAAK,iBAAiB,aAAa;IACjC,aAAa,YAAY,KAAK,MAAM,WAAW,EAAE,QAAQ,CAAC;IAC1D,SAAS,KAAK,SAAS;IACvB,cAAc,KAAK,SAAS;IAC5B,sBAAsB,KAAK,SAAS;GACtC,CAAC;GAGD,KAAK,eAAe,YAAY;IAC9B,KAAK,iBAAiB,KAAA;GACxB,CAAC;EACH;EACA,OAAO,KAAK;CACd;;;;;;;CAQA,MACE,OACA,OACM;EACN,MAAM,WAAW,KAAK,eAAe,IAAI,KAAK;EAC9C,IAAI,UAAU;GACZ,MAAM,YAAgC;IAAE,MAAM;IAAO,OAAO,KAAK,SAAS;IAAG,GAAG;GAAM;GACtF,SAAS,SAAS,YAAY,QAAQ,SAAS,CAAC;EAClD;EAEA,IAAI,UAAU,gBAAgB,UAAU,kBAAkB,UAAU,gBAClE,KAAK,MAAM,aAAa;CAE5B;;;;;;;CAQA,mBAAwC;EACtC,MAAM,YAAY,SAAS,cAAc,KAAK;EAC9C,UAAU,YAAY,uDACpB,KAAK,SAAS,YAAY,IAAI,KAAK,SAAS,cAAc;EAI5D,MAAM,YAAY,SAAS,cAAc,QAAQ;EACjD,UAAU,YAAY;EACtB,UAAU,OAAO;EACjB,UAAU,aAAa,cAAc,KAAK,SAAS,KAAK;EAGxD,UAAU,YAAY;;;;;;;;;;;;EAYtB,UAAU,iBAAiB,eAAe,KAAK,OAAO,CAAC;EAEvD,UAAU,YAAY,SAAS;EAE/B,OAAO;CACT;;;;;;;CAQA,eAAoC;EAClC,MAAM,QAAQ,SAAS,cAAc,KAAK;EAC1C,MAAM,YAAY;EAClB,MAAM,MAAM,QAAQ,GAAG,KAAK,SAAS,WAAW;EAGhD,MAAM,SAAS,SAAS,cAAc,KAAK;EAC3C,OAAO,YAAY;EAEnB,MAAM,QAAQ,SAAS,cAAc,MAAM;EAC3C,MAAM,YAAY;EAClB,MAAM,cAAc,KAAK,SAAS;EAElC,MAAM,WAAW,SAAS,cAAc,QAAQ;EAChD,SAAS,YAAY;EACrB,SAAS,OAAO;EAChB,SAAS,aAAa,cAAc,aAAa;EACjD,SAAS,YAAY;EACrB,SAAS,iBAAiB,eAAe,KAAK,SAAS,CAAC;EAExD,OAAO,YAAY,KAAK;EACxB,OAAO,YAAY,QAAQ;EAG3B,MAAM,UAAU,SAAS,cAAc,KAAK;EAC5C,QAAQ,YAAY;EACpB,KAAK,WAAW;EAEhB,MAAM,YAAY,MAAM;EACxB,MAAM,YAAY,OAAO;EAEzB,IAAI,KAAK,SAAS,WAChB,KAAK,kBAAkB,KAAK;EAG9B,OAAO;CACT;;;;;;;;;CAUA,kBAA0B,OAA0B;EAClD,KAAK,MAAM,QAAQ,CAAC,QAAQ,OAAO,GAAY;GAC7C,MAAM,SAAS,SAAS,cAAc,KAAK;GAC3C,OAAO,YAAY,sDAAsD;GACzE,OAAO,aAAa,eAAe,MAAM;GACzC,OAAO,iBAAiB,gBAAgB,UACtC,KAAK,aAAa,OAAO,MAAM,OAAO,MAAM,CAC9C;GACA,MAAM,YAAY,MAAM;EAC1B;CACF;;;;;;;;;;;;;;;CAgBA,aACE,OACA,MACA,OACA,QACM;EACN,IAAI,CAAC,KAAK,eAAe;EACzB,MAAM,eAAe;EAErB,MAAM,gBAAgB;EAEtB,MAAM,UAAU,KAAK,cAAc,sBAAsB;EACzD,MAAM,OAAO,MAAM,sBAAsB;EACzC,MAAM,SAAS,MAAM;EACrB,MAAM,SAAS,MAAM;EACrB,MAAM,aAAa,KAAK;EACxB,MAAM,cAAc,KAAK;EACzB,MAAM,YAAY,KAAK,OAAO,QAAQ;EACtC,MAAM,aAAa,KAAK;EACxB,MAAM,WAAW,KAAK;EAEtB,MAAM,cAAc;EAGpB,MAAM,WAAW,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,QAAQ,QAAQ,IAAI,WAAW,CAAC;EAC7E,MAAM,YAAY,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,QAAQ,SAAS,IAAI,WAAW,CAAC;EAK/E,MAAM,MAAM,OAAO,GAAG,UAAU;EAChC,MAAM,MAAM,MAAM,GAAG,WAAW,QAAQ,IAAI;EAC5C,MAAM,MAAM,QAAQ;EACpB,MAAM,MAAM,SAAS;EACrB,MAAM,MAAM,WAAW;EACvB,MAAM,MAAM,YAAY;EAExB,MAAM,UAAU,cAA4B;GAC1C,MAAM,KAAK,UAAU,UAAU;GAC/B,MAAM,KAAK,UAAU,UAAU;GAE/B,MAAM,YAAY,KAAK,IAAI,WAAW,QAAQ,SAAS,WAAW,WAAW;GAC7E,MAAM,aAAa,KAAK,IAAI,WAAW,KAAK,IAAI,cAAc,IAAI,SAAS,CAAC;GAE5E,IAAI;GACJ,IAAI,WAAW;GACf,IAAI,SAAS,SAAS;IACpB,MAAM,WAAW,KAAK,IAAI,UAAU,QAAQ,QAAQ,KAAK,OAAO,WAAW;IAC3E,YAAY,KAAK,IAAI,UAAU,KAAK,IAAI,aAAa,IAAI,QAAQ,CAAC;GACpE,OAAO;IACL,MAAM,WAAW,KAAK,IAAI,UAAU,aAAa,QAAQ,OAAO,WAAW;IAC3E,YAAY,KAAK,IAAI,UAAU,KAAK,IAAI,aAAa,IAAI,QAAQ,CAAC;IAElE,WAAW,aAAa,aAAa;GACvC;GAEA,MAAM,MAAM,QAAQ,GAAG,UAAU;GACjC,MAAM,MAAM,SAAS,GAAG,WAAW;GACnC,MAAM,MAAM,OAAO,GAAG,SAAS;GAC/B,KAAK,aAAa;GAClB,KAAK,cAAc;EACrB;EAEA,MAAM,gBAAgB;GACpB,OAAO,wBAAwB,MAAM,SAAS;GAC9C,OAAO,oBAAoB,eAAe,MAAM;GAChD,OAAO,oBAAoB,aAAa,OAAO;GAC/C,OAAO,oBAAoB,iBAAiB,OAAO;GACnD,KAAK,qBAAqB;EAC5B;EAEA,OAAO,oBAAoB,MAAM,SAAS;EAC1C,OAAO,iBAAiB,eAAe,MAAM;EAC7C,OAAO,iBAAiB,aAAa,OAAO;EAC5C,OAAO,iBAAiB,iBAAiB,OAAO;EAChD,KAAK,qBAAqB;CAC5B;;;;CAKA,uBAAqC;EAInC,IAAI,KAAK,SAAS,wBAAwB,OAAO;GAC/C,KAAK,wBAAwB,MAAkB;IAC7C,MAAM,SAAS,EAAE;IAGjB,IAAI,CAAC,OAAO,aAAa;IACzB,IACE,KAAK,cACL,KAAK,UACL,CAAC,KAAK,WAAW,SAAS,MAAM,KAChC,CAAC,KAAK,OAAO,SAAS,MAAM,GAE5B,KAAK,SAAS;GAElB;GACA,SAAS,iBAAiB,SAAS,KAAK,oBAAoB;EAC9D;EAGA,KAAK,uBAAuB;GAC1B,IAAI,CAAC,KAAK,OAAO,WACf,KAAK,qBAAqB;EAE9B;EACA,OAAO,iBAAiB,UAAU,KAAK,cAAc;EAGrD,KAAK,0BAA0B;GAC7B,IAAI,CAAC,KAAK,OAAO,WACf,KAAK,qBAAqB;EAE9B;EACA,KAAK,MAAM,GAAG,UAAU,KAAK,iBAAiB;CAChD;;;;;;CAOA,sBAAyF;EACvF,MAAM,SAAS,KAAK,YAAY;EAChC,IAAI,CAAC,QAAQ,OAAO;EAEpB,IAAI,OAAO,UAAU,SAAS,0BAA0B,GAAG,OAAO;EAClE,IAAI,OAAO,UAAU,SAAS,2BAA2B,GAAG,OAAO;EACnE,IAAI,OAAO,UAAU,SAAS,6BAA6B,GAAG,OAAO;EACrE,IAAI,OAAO,UAAU,SAAS,8BAA8B,GAAG,OAAO;EAEtE,OAAO;CACT;;;;;CAMA,uBAAqC;EACnC,IAAI,CAAC,KAAK,cAAc,CAAC,KAAK,UAAU,CAAC,KAAK,eAAe;EAG7D,MAAM,SAAS,KAAK,WAAW,cAAc,wBAAwB;EACrE,IAAI,CAAC,QAAQ;EAEb,MAAM,aAAa,OAAO,sBAAsB;EAChD,MAAM,UAAU,KAAK,cAAc,sBAAsB;EACzD,MAAM,WAAW,KAAK,oBAAoB;EAG1C,MAAM,YAAY,WAAW,MAAM,QAAQ;EAC3C,MAAM,eAAe,QAAQ,SAAS,WAAW;EACjD,MAAM,aAAa,WAAW,OAAO,QAAQ;EAC7C,MAAM,cAAc,QAAQ,QAAQ,WAAW;EAE/C,MAAM,WAAW;EAGjB,KAAK,OAAO,MAAM,MAAM;EACxB,KAAK,OAAO,MAAM,SAAS;EAC3B,KAAK,OAAO,MAAM,OAAO;EACzB,KAAK,OAAO,MAAM,QAAQ;EAE1B,QAAQ,UAAR;GACE,KAAK;IAEH,KAAK,OAAO,MAAM,MAAM,GAAG,YAAY,WAAW,SAAS,SAAS;IACpE,KAAK,OAAO,MAAM,OAAO,GAAG,WAAW;IACvC;GAEF,KAAK;IAEH,KAAK,OAAO,MAAM,MAAM,GAAG,YAAY,WAAW,SAAS,SAAS;IACpE,KAAK,OAAO,MAAM,QAAQ,GAAG,YAAY;IACzC;GAEF,KAAK;IAEH,KAAK,OAAO,MAAM,SAAS,GAAG,eAAe,WAAW,SAAS,SAAS;IAC1E,KAAK,OAAO,MAAM,OAAO,GAAG,WAAW;IACvC;GAEF,KAAK;IAEH,KAAK,OAAO,MAAM,SAAS,GAAG,eAAe,WAAW,SAAS,SAAS;IAC1E,KAAK,OAAO,MAAM,QAAQ,GAAG,YAAY;IACzC;EACJ;EAIA,MAAM,aAAa;EACnB,MAAM,YACH,SAAS,WAAW,KAAK,IAAI,YAAY,gBAAgB,WAAW,SAAS;EAChF,MAAM,YAAY,QAAQ,SAAS,WAAW;EAC9C,KAAK,OAAO,MAAM,YAAY,GAAG,KAAK,IAAI,KAAK,SAAS,EAAE;EAC1D,MAAM,iBAAiB,KAAK,IAAI,KAAK,QAAQ,QAAQ,IAAI,UAAU;EACnE,KAAK,OAAO,MAAM,WAAW,GAAG,eAAe;EAG/C,KAAK,OAAO,MAAM,WAAW,GAAG,KAAK,IAAI,KAAK,cAAc,EAAE;EAK9D,IAAI,KAAK,eAAe,MACtB,KAAK,OAAO,MAAM,QAAQ,GAAG,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,YAAY,cAAc,CAAC,EAAE;EAExF,IAAI,KAAK,gBAAgB,MACvB,KAAK,OAAO,MAAM,SAAS,GAAG,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,aAAa,SAAS,CAAC,EAAE;CAEvF;AACF"}