{"version":3,"file":"worksheet-C6CWgvP5.mjs","names":[],"sources":["../src/worksheet/cell-range.ts","../src/styles/colors.ts","../src/worksheet/dimensions.ts","../src/worksheet/hyperlinks.ts","../src/worksheet/views.ts","../src/worksheet/comments.ts","../src/worksheet/properties.ts","../src/worksheet/worksheet.ts"],"sourcesContent":["// Cell-range value object + set operations.\n//\n// The struct is the same `CellRangeBoundaries` we already use across the\n// coordinate parser; this module adds the worksheet-level operations\n// (containment, shift, union, intersection, iteration) and a `MultiCellRange`\n// lite wrapper for sqref-style attributes.\n\nimport type { Cell } from '../cell/cell';\nimport {\n  boundariesToRangeString,\n  type CellRangeBoundaries,\n  coordinateToTuple,\n  MAX_COL,\n  MAX_ROW,\n  rangeBoundaries,\n  tupleToCoordinate,\n} from '../utils/coordinate';\nimport { OpenXmlSchemaError } from '../utils/exceptions';\n\n/** Re-export under the plan's canonical name. */\nexport type CellRange = CellRangeBoundaries;\n\n/** Build a CellRange from explicit 1-based bounds. */\nexport function makeCellRange(minRow: number, minCol: number, maxRow: number, maxCol: number): CellRange {\n  if (\n    !Number.isInteger(minRow) ||\n    !Number.isInteger(minCol) ||\n    !Number.isInteger(maxRow) ||\n    !Number.isInteger(maxCol)\n  ) {\n    throw new OpenXmlSchemaError('CellRange bounds must be integers');\n  }\n  if (minRow < 1 || maxRow < 1 || minRow > MAX_ROW || maxRow > MAX_ROW) {\n    throw new OpenXmlSchemaError(`CellRange row bounds must be in [1, ${MAX_ROW}]`);\n  }\n  if (minCol < 1 || maxCol < 1 || minCol > MAX_COL || maxCol > MAX_COL) {\n    throw new OpenXmlSchemaError(`CellRange col bounds must be in [1, ${MAX_COL}]`);\n  }\n  return {\n    minRow: Math.min(minRow, maxRow),\n    minCol: Math.min(minCol, maxCol),\n    maxRow: Math.max(minRow, maxRow),\n    maxCol: Math.max(minCol, maxCol),\n  };\n}\n\n/** Parse a range expression — wraps {@link rangeBoundaries}. */\nexport function parseRange(input: string): CellRange {\n  return rangeBoundaries(input);\n}\n\n/** Format a CellRange back into the canonical OOXML string. */\nexport function rangeToString(r: CellRange): string {\n  return boundariesToRangeString(r);\n}\n\n/**\n * Compute the bounding A1-style range string for a list of cells. Walks the\n * input once to find min/max row+col. A single-cell input returns a single-cell\n * ref (`\"A1\"`); two or more cells (even collinear) return the `\"A1:B5\"` form.\n *\n * Throws when the array is empty — there's no meaningful zero-cell range, and\n * silently returning `\"\"` would defeat downstream `parseRange` consumers.\n */\nexport function cellRangeFromCells(cells: ReadonlyArray<Pick<Cell, 'row' | 'col'>>): string {\n  if (cells.length === 0) {\n    throw new OpenXmlSchemaError('cellRangeFromCells: cells array must be non-empty');\n  }\n  let minRow = Number.POSITIVE_INFINITY;\n  let maxRow = Number.NEGATIVE_INFINITY;\n  let minCol = Number.POSITIVE_INFINITY;\n  let maxCol = Number.NEGATIVE_INFINITY;\n  for (const c of cells) {\n    if (c.row < minRow) minRow = c.row;\n    if (c.row > maxRow) maxRow = c.row;\n    if (c.col < minCol) minCol = c.col;\n    if (c.col > maxCol) maxCol = c.col;\n  }\n  if (minRow === maxRow && minCol === maxCol) {\n    return tupleToCoordinate(minCol, minRow);\n  }\n  return boundariesToRangeString({ minRow, minCol, maxRow, maxCol });\n}\n\n/** Inclusive containment of a single (row, col) within a range. */\nexport function rangeContainsCell(r: CellRange, row: number, col: number): boolean {\n  return row >= r.minRow && row <= r.maxRow && col >= r.minCol && col <= r.maxCol;\n}\n\n/**\n * A1-string convenience for {@link rangeContainsCell}. Parses `cellRef` (e.g.\n * `\"B3\"`) and `rangeRef` (e.g. `\"A1:C5\"`) and returns `true` iff the cell sits\n * inside the range (boundary-inclusive). Throws when either input is malformed.\n */\nexport function isCellInRange(cellRef: string, rangeRef: string): boolean {\n  const { col, row } = coordinateToTuple(cellRef);\n  return rangeContainsCell(parseRange(rangeRef), row, col);\n}\n\n/**\n * A1-string convenience for {@link rangeContainsRange}. Returns `true` iff the\n * `inner` range is wholly contained by `outer` (boundary-inclusive).\n * Single-cell refs are accepted on either side via parseRange. Throws on\n * malformed input.\n */\nexport function isRangeInRange(inner: string, outer: string): boolean {\n  return rangeContainsRange(parseRange(outer), parseRange(inner));\n}\n\n/**\n * A1-string convenience for {@link rangesOverlap}. Returns `true` iff the two\n * ranges share at least one cell. Boundary-inclusive (a 1-row gap = no\n * overlap). Single-cell refs are accepted via parseRange. Throws on malformed\n * input.\n */\nexport function rangesOverlapStr(a: string, b: string): boolean {\n  return rangesOverlap(parseRange(a), parseRange(b));\n}\n\n/**\n * A1-string convenience for {@link unionRange}. Returns the smallest A1 range\n * that contains both inputs (always non-null; ranges that don't overlap still\n * get a valid bounding box).\n */\nexport function unionRangeStr(a: string, b: string): string {\n  return rangeToString(unionRange(parseRange(a), parseRange(b)));\n}\n\n/**\n * A1-string convenience for {@link intersectionRange}. Returns the shared\n * rectangular sub-range as A1 string, or `undefined` when the inputs are\n * disjoint.\n */\nexport function intersectionRangeStr(a: string, b: string): string | undefined {\n  const r = intersectionRange(parseRange(a), parseRange(b));\n  return r === null ? undefined : rangeToString(r);\n}\n\n/**\n * A1-string convenience for {@link shiftRange}. Translates the range by `(dr,\n * dc)` integer offsets and re-serialises. Negative offsets shift up/left.\n * Throws when the resulting bounds fall outside the OOXML grid (rows\n * 1..1048576, cols 1..16384).\n */\nexport function shiftRangeStr(range: string, dr: number, dc: number): string {\n  return rangeToString(shiftRange(parseRange(range), dr, dc));\n}\n\n/**\n * A1-string convenience for {@link rangeArea}. Returns the inclusive cell count\n * covered by the range (rows × cols). Single-cell refs return 1.\n */\nexport function rangeAreaStr(range: string): number {\n  return rangeArea(parseRange(range));\n}\n\n/**\n * A1-string range dimensions: how many rows and columns the range spans\n * (inclusive). Distinct from {@link rangeAreaStr} which returns the product.\n * Single-cell refs return `{ rows: 1, cols: 1 }`.\n */\nexport function rangeDimensionsStr(range: string): { rows: number; cols: number } {\n  const r = parseRange(range);\n  return { rows: r.maxRow - r.minRow + 1, cols: r.maxCol - r.minCol + 1 };\n}\n\n/**\n * Expand (or shrink) an A1 range by adding `deltaRows` to its bottom edge and\n * `deltaCols` to its right edge. The top-left corner is preserved. Negative\n * deltas shrink the range; the result must still have at least 1 row and 1\n * column (otherwise throws).\n *\n * Useful for \"this is the data range — also reserve room for a totals row\" or\n * \"include one more column to the right\" patterns.\n */\nexport function expandRangeStr(range: string, deltaRows: number, deltaCols: number): string {\n  if (!Number.isInteger(deltaRows) || !Number.isInteger(deltaCols)) {\n    throw new OpenXmlSchemaError('expandRangeStr: deltas must be integers');\n  }\n  const r = parseRange(range);\n  return rangeToString(makeCellRange(r.minRow, r.minCol, r.maxRow + deltaRows, r.maxCol + deltaCols));\n}\n\n/** Inclusive containment of `inner` within `outer`. */\nexport function rangeContainsRange(outer: CellRange, inner: CellRange): boolean {\n  return (\n    inner.minRow >= outer.minRow &&\n    inner.maxRow <= outer.maxRow &&\n    inner.minCol >= outer.minCol &&\n    inner.maxCol <= outer.maxCol\n  );\n}\n\n/**\n * Shift a range by (dr, dc) integer offsets. The returned range is clamped to\n * the OOXML grid; callers that want hard bounds should pass values that keep\n * the result inside the spec.\n */\nexport function shiftRange(r: CellRange, dr: number, dc: number): CellRange {\n  if (!Number.isInteger(dr) || !Number.isInteger(dc)) {\n    throw new OpenXmlSchemaError('shiftRange: dr / dc must be integers');\n  }\n  return makeCellRange(r.minRow + dr, r.minCol + dc, r.maxRow + dr, r.maxCol + dc);\n}\n\n/** Bounding-box union of two ranges. Always non-null. */\nexport function unionRange(a: CellRange, b: CellRange): CellRange {\n  return {\n    minRow: Math.min(a.minRow, b.minRow),\n    minCol: Math.min(a.minCol, b.minCol),\n    maxRow: Math.max(a.maxRow, b.maxRow),\n    maxCol: Math.max(a.maxCol, b.maxCol),\n  };\n}\n\n/** Returns the rectangular intersection of two ranges, or `null` when disjoint. */\nexport function intersectionRange(a: CellRange, b: CellRange): CellRange | null {\n  const minRow = Math.max(a.minRow, b.minRow);\n  const minCol = Math.max(a.minCol, b.minCol);\n  const maxRow = Math.min(a.maxRow, b.maxRow);\n  const maxCol = Math.min(a.maxCol, b.maxCol);\n  if (minRow > maxRow || minCol > maxCol) return null;\n  return { minRow, minCol, maxRow, maxCol };\n}\n\n/** True iff two ranges share at least one cell. */\nexport function rangesOverlap(a: CellRange, b: CellRange): boolean {\n  return intersectionRange(a, b) !== null;\n}\n\n/** Inclusive cell count covered by a range. */\nexport function rangeArea(r: CellRange): number {\n  return (r.maxRow - r.minRow + 1) * (r.maxCol - r.minCol + 1);\n}\n\n/** Yield every (row, col) coordinate in the range, row-major. */\nexport function* iterRangeCoordinates(r: CellRange): IterableIterator<{ row: number; col: number }> {\n  for (let row = r.minRow; row <= r.maxRow; row++) {\n    for (let col = r.minCol; col <= r.maxCol; col++) {\n      yield { row, col };\n    }\n  }\n}\n\n// ---- MultiCellRange --------------------------------------------------------\n\n/**\n * Excel's `sqref` attribute: a space-separated list of CellRanges. Used by data\n * validations, conditional formatting, hyperlinks etc.\n */\nexport interface MultiCellRange {\n  ranges: CellRange[];\n}\n\nexport function makeMultiCellRange(ranges: ReadonlyArray<CellRange> = []): MultiCellRange {\n  return { ranges: ranges.slice() };\n}\n\n/** Parse an sqref string: `\"A1:B2 D5 E10:F20\"`. Whitespace-delimited. */\nexport function parseMultiCellRange(input: string): MultiCellRange {\n  const ranges: CellRange[] = [];\n  for (const piece of input.split(/\\s+/)) {\n    if (piece.length === 0) continue;\n    ranges.push(parseRange(piece));\n  }\n  return { ranges };\n}\n\n/** Format a MultiCellRange back into an sqref string. */\nexport function multiCellRangeToString(m: MultiCellRange): string {\n  return m.ranges.map(rangeToString).join(' ');\n}\n\n/** Total cell count across all ranges (no de-duplication of overlaps). */\nexport function multiCellRangeArea(m: MultiCellRange): number {\n  let n = 0;\n  for (const r of m.ranges) n += rangeArea(r);\n  return n;\n}\n\n/** True iff any contained range covers (row, col). */\nexport function multiCellRangeContainsCell(m: MultiCellRange, row: number, col: number): boolean {\n  for (const r of m.ranges) if (rangeContainsCell(r, row, col)) return true;\n  return false;\n}\n","// Color value object. Mirrors openpyxl/openpyxl/styles/colors.py.\n//\n// Excel exposes four mutually-exclusive ways to specify a colour:\n//   * rgb     — explicit aRGB hex (\"AARRGGBB\"); 6-hex inputs auto-pad to 00..\n//   * indexed — 0-63 index into the legacy COLOR_INDEX palette (plus 64/65\n//                reserved for the system fg/bg).\n//   * theme   — 0-N index into the workbook's theme colour scheme.\n//   * auto    — boolean \"use system default\".\n//\n// These are plain readonly objects; `makeColor` freezes its result so the\n// Stylesheet pool can dedupe by reference equality.\n\nimport { OpenXmlSchemaError } from '../utils/exceptions';\n\n/**\n * Colour reference. All fields are optional but Excel expects exactly one of\n * {rgb, indexed, theme, auto} to be set; if none is, the cell inherits the\n * parent style's colour.\n *\n * `tint` modulates the resolved colour; -1 = full black, +1 = full white.\n */\nexport interface Color {\n  /** \"AARRGGBB\" hex (uppercase). 6-hex inputs are auto-padded with `00` alpha. */\n  readonly rgb?: string;\n  /** 0..63 → COLOR_INDEX entry. 64 = system foreground, 65 = system background. */\n  readonly indexed?: number;\n  /** Theme colour index. */\n  readonly theme?: number;\n  /** \"Auto\" / system default. */\n  readonly auto?: boolean;\n  /** Lightness modulation in [-1, 1]. */\n  readonly tint?: number;\n}\n\n/**\n * Legacy 64-entry palette indexed colours fall back to. Verbatim from\n * openpyxl/openpyxl/styles/colors.py — must not be reordered.\n */\nexport const COLOR_INDEX: readonly string[] = Object.freeze([\n  '00000000',\n  '00FFFFFF',\n  '00FF0000',\n  '0000FF00',\n  '000000FF', // 0-4\n  '00FFFF00',\n  '00FF00FF',\n  '0000FFFF',\n  '00000000',\n  '00FFFFFF', // 5-9\n  '00FF0000',\n  '0000FF00',\n  '000000FF',\n  '00FFFF00',\n  '00FF00FF', // 10-14\n  '0000FFFF',\n  '00800000',\n  '00008000',\n  '00000080',\n  '00808000', // 15-19\n  '00800080',\n  '00008080',\n  '00C0C0C0',\n  '00808080',\n  '009999FF', // 20-24\n  '00993366',\n  '00FFFFCC',\n  '00CCFFFF',\n  '00660066',\n  '00FF8080', // 25-29\n  '000066CC',\n  '00CCCCFF',\n  '00000080',\n  '00FF00FF',\n  '00FFFF00', // 30-34\n  '0000FFFF',\n  '00800080',\n  '00800000',\n  '00008080',\n  '000000FF', // 35-39\n  '0000CCFF',\n  '00CCFFFF',\n  '00CCFFCC',\n  '00FFFF99',\n  '0099CCFF', // 40-44\n  '00FF99CC',\n  '00CC99FF',\n  '00FFCC99',\n  '003366FF',\n  '0033CCCC', // 45-49\n  '0099CC00',\n  '00FFCC00',\n  '00FF9900',\n  '00FF6600',\n  '00666699', // 50-54\n  '00969696',\n  '00003366',\n  '00339966',\n  '00003300',\n  '00333300', // 55-59\n  '00993300',\n  '00993366',\n  '00333399',\n  '00333333', // 60-63\n]);\n\n/**\n * Convenience constants — match openpyxl's exports. Inlined rather than indexed\n * off COLOR_INDEX to keep the type system from widening to `string | undefined`\n * on tuple lookup.\n */\nexport const BLACK = '00000000';\nexport const WHITE = '00FFFFFF';\nexport const BLUE = '000000FF';\n\nconst ARGB_RE = /^([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6})$/;\n\n/**\n * Normalise an aRGB hex string. Accepts either 6 or 8 hex digits; 6-digit input\n * is padded to 8 by prefixing `00` (alpha=0 = fully opaque per Excel\n * convention). Returns the canonical uppercase form.\n */\nexport function normaliseRgb(value: string): string {\n  if (typeof value !== 'string' || !ARGB_RE.test(value)) {\n    throw new OpenXmlSchemaError(`Color rgb must be 6 or 8 hex digits; got \"${value}\"`);\n  }\n  return (value.length === 6 ? `00${value}` : value).toUpperCase();\n}\n\n/**\n * Build an immutable {@link Color}. Validates ranges (indexed in [0, 65], tint\n * in [-1, 1]) and normalises rgb hex.\n */\nexport function makeColor(opts: Partial<Color> = {}): Color {\n  const out: Mutable<Color> = {};\n  if (opts.rgb !== undefined) out.rgb = normaliseRgb(opts.rgb);\n  if (opts.indexed !== undefined) {\n    if (!Number.isInteger(opts.indexed) || opts.indexed < 0 || opts.indexed > 65) {\n      throw new OpenXmlSchemaError(`Color indexed must be in [0, 65]; got ${opts.indexed}`);\n    }\n    out.indexed = opts.indexed;\n  }\n  if (opts.theme !== undefined) {\n    if (!Number.isInteger(opts.theme) || opts.theme < 0) {\n      throw new OpenXmlSchemaError(`Color theme must be a non-negative integer; got ${opts.theme}`);\n    }\n    out.theme = opts.theme;\n  }\n  if (opts.auto !== undefined) out.auto = opts.auto;\n  if (opts.tint !== undefined) {\n    if (!Number.isFinite(opts.tint) || opts.tint < -1 || opts.tint > 1) {\n      throw new OpenXmlSchemaError(`Color tint must be in [-1, 1]; got ${opts.tint}`);\n    }\n    out.tint = opts.tint;\n  }\n  return Object.freeze(out);\n}\n\n/**\n * Resolve `indexed` references against {@link COLOR_INDEX}. Returns undefined\n * for 64/65 (system fg/bg, not in the palette) or out-of-range.\n */\nexport function resolveIndexedColor(idx: number): string | undefined {\n  return COLOR_INDEX[idx];\n}\n\n/** Shortcut for the common opaque solid colour. */\nexport function rgbColor(hex: string): Color {\n  return makeColor({ rgb: hex });\n}\n\n/**\n * Read a {@link Color} value-object back to a normalised ARGB hex. Resolution\n * order: explicit `rgb` → `indexed` palette lookup. Returns `undefined` for\n * `theme` / `auto` / empty inputs (unresolvable without a theme), so callers\n * can fall back to a default.\n */\nexport function colorToHex(color: Color | undefined): string | undefined {\n  if (!color) return undefined;\n  if (color.rgb !== undefined) return normaliseRgb(color.rgb);\n  if (color.indexed !== undefined) {\n    const rgb = resolveIndexedColor(color.indexed);\n    if (rgb) return rgb.toUpperCase();\n  }\n  return undefined;\n}\n\n/**\n * Compute the relative luminance of an ARGB / RGB hex string per the WCAG 2.x\n * formula. Returns a value in `[0, 1]` where 0 is black and 1 is white. The\n * alpha channel (if present) is ignored.\n */\nexport function luminance(hex: string): number {\n  const rgb = normaliseRgb(hex); // 8-char AARRGGBB upper-case\n  const r = Number.parseInt(rgb.slice(2, 4), 16) / 255;\n  const g = Number.parseInt(rgb.slice(4, 6), 16) / 255;\n  const b = Number.parseInt(rgb.slice(6, 8), 16) / 255;\n  const lin = (c: number): number => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);\n  return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);\n}\n\n/**\n * WCAG contrast ratio between two ARGB hex colors. Returns a value in `[1,\n * 21]`; 1 = identical luminance, 21 = pure black on pure white. The order of\n * arguments doesn't matter.\n */\nexport function contrastRatio(hexA: string, hexB: string): number {\n  const lA = luminance(hexA);\n  const lB = luminance(hexB);\n  const [hi, lo] = lA >= lB ? [lA, lB] : [lB, lA];\n  return (hi + 0.05) / (lo + 0.05);\n}\n\n/**\n * Pick the higher-contrast text color (`'FF000000'` black or `'FFFFFFFF'`\n * white) for a background hex. Useful when applying a solid fill and wanting\n * the cell text to stay readable.\n */\nexport function pickReadableTextColor(backgroundHex: string): 'FF000000' | 'FFFFFFFF' {\n  // WCAG midpoint of 0.179 splits \"near-black bg → white text\" from \"lighter bg\n  // → black text\".\n  return luminance(backgroundHex) < 0.179 ? 'FFFFFFFF' : 'FF000000';\n}\n\nconst splitArgb = (hex: string): { a: number; r: number; g: number; b: number } => {\n  const rgb = normaliseRgb(hex);\n  return {\n    a: Number.parseInt(rgb.slice(0, 2), 16),\n    r: Number.parseInt(rgb.slice(2, 4), 16),\n    g: Number.parseInt(rgb.slice(4, 6), 16),\n    b: Number.parseInt(rgb.slice(6, 8), 16),\n  };\n};\n\nconst toHexByte = (n: number): string => {\n  const v = Math.max(0, Math.min(255, Math.round(n)));\n  return v.toString(16).padStart(2, '0').toUpperCase();\n};\n\nconst clampUnit = (x: number): number => Math.max(0, Math.min(1, x));\n\n/**\n * Lighten a color by mixing it with white. `amount` is in `[0, 1]`: 0 returns\n * the input unchanged, 1 returns pure white. Alpha channel is preserved.\n * Equivalent to `mixColors(hex, 'FFFFFFFF', amount)`.\n */\nexport function lighten(hex: string, amount: number): string {\n  const t = clampUnit(amount);\n  const { a, r, g, b } = splitArgb(hex);\n  return `${toHexByte(a)}${toHexByte(r + (255 - r) * t)}${toHexByte(g + (255 - g) * t)}${toHexByte(b + (255 - b) * t)}`;\n}\n\n/**\n * Darken a color by mixing it with black. `amount` is in `[0, 1]`: 0 returns\n * the input unchanged, 1 returns pure black (preserving the alpha channel).\n */\nexport function darken(hex: string, amount: number): string {\n  const t = clampUnit(amount);\n  const { a, r, g, b } = splitArgb(hex);\n  return `${toHexByte(a)}${toHexByte(r * (1 - t))}${toHexByte(g * (1 - t))}${toHexByte(b * (1 - t))}`;\n}\n\n/**\n * Linearly interpolate between two ARGB colors. `t = 0` returns `hexA`; `t = 1`\n * returns `hexB`; intermediate values mix per channel (including alpha).\n */\nexport function mixColors(hexA: string, hexB: string, t: number): string {\n  const k = clampUnit(t);\n  const a = splitArgb(hexA);\n  const b = splitArgb(hexB);\n  return `${toHexByte(a.a + (b.a - a.a) * k)}${toHexByte(a.r + (b.r - a.r) * k)}${toHexByte(a.g + (b.g - a.g) * k)}${toHexByte(a.b + (b.b - a.b) * k)}`;\n}\n\n/**\n * Convert an ARGB / RGB hex to its HSL representation. Returns `{ h, s, l, a }`\n * with `h ∈ [0, 360)`, `s ∈ [0, 1]`, `l ∈ [0, 1]`, `a ∈ [0, 255]` (alpha as the\n * original byte). Useful for theme tweaking (rotate hue, desaturate, etc.)\n * before round-tripping through {@link hslToHex}.\n */\nexport function hexToHsl(hex: string): { h: number; s: number; l: number; a: number } {\n  const { a, r: rb, g: gb, b: bb } = splitArgb(hex);\n  const r = rb / 255;\n  const g = gb / 255;\n  const b = bb / 255;\n  const max = Math.max(r, g, b);\n  const min = Math.min(r, g, b);\n  const l = (max + min) / 2;\n  let h = 0;\n  let s = 0;\n  if (max !== min) {\n    const d = max - min;\n    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n    if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) * 60;\n    else if (max === g) h = ((b - r) / d + 2) * 60;\n    else h = ((r - g) / d + 4) * 60;\n  }\n  return { h, s, l, a };\n}\n\n/**\n * Rotate the hue of a color by `degrees` (positive = clockwise). Saturation and\n * lightness are preserved; alpha is preserved. Equivalent to `hexToHsl` →\n * adjust `h` → `hslToHex`.\n */\nexport function rotateHue(hex: string, degrees: number): string {\n  const { h, s, l, a } = hexToHsl(hex);\n  return hslToHex(h + degrees, s, l, a);\n}\n\n/**\n * Adjust the saturation of a color by `delta` (added directly to the `[0, 1]`\n * saturation channel and clamped). Positive = more vivid, negative = closer to\n * gray. Hue, lightness, and alpha are preserved.\n */\nexport function adjustSaturation(hex: string, delta: number): string {\n  const { h, s, l, a } = hexToHsl(hex);\n  return hslToHex(h, s + delta, l, a);\n}\n\n/**\n * Adjust the lightness of a color by `delta` (added directly to the `[0, 1]`\n * lightness channel and clamped). Positive = lighter, negative = darker.\n * Distinct from {@link lighten} / {@link darken} which mix toward white/black\n * in RGB space.\n */\nexport function adjustLightness(hex: string, delta: number): string {\n  const { h, s, l, a } = hexToHsl(hex);\n  return hslToHex(h, s, l + delta, a);\n}\n\n/**\n * Convert HSL components back to an ARGB hex string. `h` wraps mod-360, `s` and\n * `l` clamp to `[0, 1]`. `alpha` is the byte (default 255 = opaque), placed in\n * the high byte of the result.\n */\nexport function hslToHex(h: number, s: number, l: number, alpha = 255): string {\n  const hh = ((h % 360) + 360) % 360;\n  const ss = clampUnit(s);\n  const ll = clampUnit(l);\n  const c = (1 - Math.abs(2 * ll - 1)) * ss;\n  const x = c * (1 - Math.abs(((hh / 60) % 2) - 1));\n  const m = ll - c / 2;\n  let rp = 0;\n  let gp = 0;\n  let bp = 0;\n  if (hh < 60) {\n    rp = c;\n    gp = x;\n  } else if (hh < 120) {\n    rp = x;\n    gp = c;\n  } else if (hh < 180) {\n    gp = c;\n    bp = x;\n  } else if (hh < 240) {\n    gp = x;\n    bp = c;\n  } else if (hh < 300) {\n    rp = x;\n    bp = c;\n  } else {\n    rp = c;\n    bp = x;\n  }\n  const a = Math.max(0, Math.min(255, Math.round(alpha)));\n  return `${toHexByte(a)}${toHexByte((rp + m) * 255)}${toHexByte((gp + m) * 255)}${toHexByte((bp + m) * 255)}`;\n}\n\n// Internal mutable mirror used inside `make*` constructors. Never leaks.\ntype Mutable<T> = { -readonly [P in keyof T]: T[P] };\n","// Column / row dimension metadata. (`columnDimensions` / `rowDimensions` Maps +\n// `defaultColumnWidth` / `defaultRowHeight`) and the openpyxl reference at\n// `worksheet/dimensions.py`.\n//\n// **Stage 1**: width / height / hidden / customWidth / customHeight / bestFit /\n// outlineLevel + style fall-back. Multi-`<col>` runs collapse per-column\n// entries when adjacent equal entries are persisted (writer side) — read keeps\n// each column its own entry so user mutations don't surprise neighbours.\n\n/**\n * Single-column-or-range dimension entry. Mirrors the OOXML `<col>` element.\n * The `min`/`max` pair always covers a contiguous run; the worksheet's\n * `columnDimensions` Map keys by `min` so per-column edits stay O(log n).\n */\nexport interface ColumnDimension {\n  /** 1-based first column the entry covers (inclusive). */\n  min: number;\n  /** 1-based last column the entry covers (inclusive). */\n  max: number;\n  /** Width in Excel character units. */\n  width?: number;\n  /** Excel records `customWidth=1` whenever the user touched the slider. */\n  customWidth?: boolean;\n  /** Hidden columns get `hidden=\"1\"`. */\n  hidden?: boolean;\n  /** \"Best fit\" auto-shrink semantics — Excel sets it for narrow columns. */\n  bestFit?: boolean;\n  /** Outline-level for grouping (0 = ungrouped). */\n  outlineLevel?: number;\n  /** Default cell xfId applied to empty cells in the column. */\n  style?: number;\n  /** Whether the column's outline is collapsed. */\n  collapsed?: boolean;\n}\n\n/** Per-row metadata. Mirrors the OOXML `<row>` element's attributes. */\nexport interface RowDimension {\n  /** Row height in points. */\n  height?: number;\n  /** Mirrors Excel's `customHeight=\"1\"` flag. */\n  customHeight?: boolean;\n  hidden?: boolean;\n  outlineLevel?: number;\n  collapsed?: boolean;\n  /** Default cell xfId applied to empty cells in the row. */\n  style?: number;\n}\n\n/** Build a single-column ColumnDimension entry covering `col`. */\nexport function makeColumnDimension(\n  col: number,\n  opts: Partial<Omit<ColumnDimension, 'min' | 'max'>> = {},\n): ColumnDimension {\n  return {\n    min: col,\n    max: col,\n    ...(opts.width !== undefined ? { width: opts.width } : {}),\n    ...(opts.customWidth !== undefined ? { customWidth: opts.customWidth } : {}),\n    ...(opts.hidden !== undefined ? { hidden: opts.hidden } : {}),\n    ...(opts.bestFit !== undefined ? { bestFit: opts.bestFit } : {}),\n    ...(opts.outlineLevel !== undefined ? { outlineLevel: opts.outlineLevel } : {}),\n    ...(opts.style !== undefined ? { style: opts.style } : {}),\n    ...(opts.collapsed !== undefined ? { collapsed: opts.collapsed } : {}),\n  };\n}\n\nexport function makeRowDimension(opts: Partial<RowDimension> = {}): RowDimension {\n  return {\n    ...(opts.height !== undefined ? { height: opts.height } : {}),\n    ...(opts.customHeight !== undefined ? { customHeight: opts.customHeight } : {}),\n    ...(opts.hidden !== undefined ? { hidden: opts.hidden } : {}),\n    ...(opts.outlineLevel !== undefined ? { outlineLevel: opts.outlineLevel } : {}),\n    ...(opts.collapsed !== undefined ? { collapsed: opts.collapsed } : {}),\n    ...(opts.style !== undefined ? { style: opts.style } : {}),\n  };\n}\n","// Worksheet hyperlinks.\n//\n// External URLs land in `xl/worksheets/_rels/sheetN.xml.rels` (one rel per\n// Hyperlink entry, type \"...relationships/hyperlink\", TargetMode=\"External\").\n// Internal jumps (`#'Sheet 2'!A1`) live entirely in the `<hyperlink\n// location=\"...\"/>` attribute and don't need a rel.\n\nimport { OpenXmlSchemaError } from '../utils/exceptions';\n\nexport interface Hyperlink {\n  /** Cell or range the hyperlink covers — \"A1\" or \"A1:B5\". */\n  ref: string;\n  /** External URL or relative target path. Mutually exclusive with `location`-only links. */\n  target?: string;\n  /** Anchor inside the workbook (e.g. `'Sheet 2'!A1`). */\n  location?: string;\n  /** Tooltip shown on hover. */\n  tooltip?: string;\n  /** Visible link text — typically falls back to the referenced cell value. */\n  display?: string;\n  /** Worksheet-rels rId. Populated on read; assigned by the writer when missing. */\n  rId?: string;\n}\n\nexport function makeHyperlink(opts: Partial<Hyperlink> & { ref: string }): Hyperlink {\n  if (opts.ref === undefined || opts.ref.length === 0) {\n    throw new OpenXmlSchemaError('Hyperlink: ref is required');\n  }\n  return {\n    ref: opts.ref,\n    ...(opts.target !== undefined ? { target: opts.target } : {}),\n    ...(opts.location !== undefined ? { location: opts.location } : {}),\n    ...(opts.tooltip !== undefined ? { tooltip: opts.tooltip } : {}),\n    ...(opts.display !== undefined ? { display: opts.display } : {}),\n    ...(opts.rId !== undefined ? { rId: opts.rId } : {}),\n  };\n}\n\n// ---- Worksheet ergonomic helpers ----------------------------------------\n\nimport type { Worksheet } from './worksheet';\n\nconst replaceHyperlink = (ws: Worksheet, hl: Hyperlink): Hyperlink => {\n  const idx = ws.hyperlinks.findIndex((h) => h.ref === hl.ref);\n  if (idx >= 0) ws.hyperlinks[idx] = hl;\n  else ws.hyperlinks.push(hl);\n  return hl;\n};\n\n/**\n * Add an external URL hyperlink to a cell or range. The URL goes into the\n * worksheet rels as a hyperlink relationship; the writer generates an rId on\n * save.\n */\nexport const addUrlHyperlink = (\n  ws: Worksheet,\n  ref: string,\n  url: string,\n  opts: { tooltip?: string; display?: string } = {},\n): Hyperlink => {\n  return replaceHyperlink(\n    ws,\n    makeHyperlink({\n      ref,\n      target: url,\n      ...(opts.tooltip !== undefined ? { tooltip: opts.tooltip } : {}),\n      ...(opts.display !== undefined ? { display: opts.display } : {}),\n    }),\n  );\n};\n\n/**\n * Add an in-workbook jump hyperlink (e.g. to `'Sheet2'!A1` or a defined-name).\n * No rels entry is written — the location is inline in the `<hyperlink\n * location=\"…\"/>` attribute.\n */\nexport const addInternalHyperlink = (\n  ws: Worksheet,\n  ref: string,\n  location: string,\n  opts: { tooltip?: string; display?: string } = {},\n): Hyperlink => {\n  return replaceHyperlink(\n    ws,\n    makeHyperlink({\n      ref,\n      location,\n      ...(opts.tooltip !== undefined ? { tooltip: opts.tooltip } : {}),\n      ...(opts.display !== undefined ? { display: opts.display } : {}),\n    }),\n  );\n};\n\n/** `mailto:` shortcut. */\nexport const addMailtoHyperlink = (\n  ws: Worksheet,\n  ref: string,\n  email: string,\n  opts: { subject?: string; tooltip?: string; display?: string } = {},\n): Hyperlink => {\n  const url = opts.subject\n    ? `mailto:${email}?subject=${encodeURIComponent(opts.subject)}`\n    : `mailto:${email}`;\n  return addUrlHyperlink(ws, ref, url, {\n    ...(opts.tooltip !== undefined ? { tooltip: opts.tooltip } : {}),\n    ...(opts.display !== undefined ? { display: opts.display } : {}),\n  });\n};\n","// SheetView / Pane / Selection. (`Worksheet.views`) + the openpyxl reference at\n// `worksheet/views.py`.\n//\n// **Stage 1**: SheetView with the most-used field subset (tabSelected, view,\n// workbookViewId, showGridLines, zoomScale, topLeftCell, pane, selection).\n// Reader / writer cover the round-trip; `setFreezePanes` builds the pane from\n// an \"A1\"-style top-left ref. Per-pane multi-selection blocks aren't widespread\n// in real-world fixtures, so stage-1 stores a single Selection.\n\nimport { coordinateToTuple, tupleToCoordinate } from '../utils/coordinate';\nimport { OpenXmlSchemaError } from '../utils/exceptions';\n\nexport type PaneType = 'bottomRight' | 'topRight' | 'bottomLeft' | 'topLeft';\nexport type PaneState = 'split' | 'frozen' | 'frozenSplit';\nexport type SheetViewMode = 'normal' | 'pageBreakPreview' | 'pageLayout';\n\nexport interface Pane {\n  /** Column-axis split. Number of columns frozen on the left. */\n  xSplit?: number;\n  /** Row-axis split. Number of rows frozen on top. */\n  ySplit?: number;\n  /** First visible cell of the bottom-right pane. */\n  topLeftCell?: string;\n  /** Which pane is active when the sheet is opened. Defaults to `bottomRight` for full freezes. */\n  activePane?: PaneType;\n  state: PaneState;\n}\n\nexport interface Selection {\n  pane?: PaneType;\n  activeCell?: string;\n  sqref?: string;\n}\n\nexport interface SheetView {\n  /** Index into the parent workbook's bookViews list. Defaults to 0. */\n  workbookViewId: number;\n  tabSelected?: boolean;\n  showGridLines?: boolean;\n  showRowColHeaders?: boolean;\n  showFormulas?: boolean;\n  showZeros?: boolean;\n  rightToLeft?: boolean;\n  view?: SheetViewMode;\n  topLeftCell?: string;\n  zoomScale?: number;\n  zoomScaleNormal?: number;\n  pane?: Pane;\n  selection?: Selection;\n}\n\n/** Build a SheetView with sensible defaults. */\nexport function makeSheetView(opts: Partial<SheetView> = {}): SheetView {\n  return {\n    workbookViewId: opts.workbookViewId ?? 0,\n    ...(opts.tabSelected !== undefined ? { tabSelected: opts.tabSelected } : {}),\n    ...(opts.showGridLines !== undefined ? { showGridLines: opts.showGridLines } : {}),\n    ...(opts.showRowColHeaders !== undefined ? { showRowColHeaders: opts.showRowColHeaders } : {}),\n    ...(opts.showFormulas !== undefined ? { showFormulas: opts.showFormulas } : {}),\n    ...(opts.showZeros !== undefined ? { showZeros: opts.showZeros } : {}),\n    ...(opts.rightToLeft !== undefined ? { rightToLeft: opts.rightToLeft } : {}),\n    ...(opts.view !== undefined ? { view: opts.view } : {}),\n    ...(opts.topLeftCell !== undefined ? { topLeftCell: opts.topLeftCell } : {}),\n    ...(opts.zoomScale !== undefined ? { zoomScale: opts.zoomScale } : {}),\n    ...(opts.zoomScaleNormal !== undefined ? { zoomScaleNormal: opts.zoomScaleNormal } : {}),\n    ...(opts.pane ? { pane: opts.pane } : {}),\n    ...(opts.selection ? { selection: opts.selection } : {}),\n  };\n}\n\n/**\n * Build a frozen Pane from a top-left coordinate. Per Excel semantics:\n * - \"B2\" → freeze 1 row + 1 col → xSplit=1, ySplit=1, activePane='bottomRight'\n * - \"A2\" → freeze 1 row only → ySplit=1, activePane='bottomLeft'\n * - \"B1\" → freeze 1 col only → xSplit=1, activePane='topRight'\n * - \"A1\" → no freeze; throws (caller should clear `ws.views[].pane`).\n */\nexport function makeFreezePane(topLeftRef: string): Pane {\n  const { col, row } = coordinateToTuple(topLeftRef);\n  if (col === 1 && row === 1) {\n    throw new OpenXmlSchemaError('makeFreezePane: \"A1\" is not a valid freeze ref (no rows or columns to freeze)');\n  }\n  const xSplit = col - 1;\n  const ySplit = row - 1;\n  let activePane: PaneType;\n  if (xSplit > 0 && ySplit > 0) activePane = 'bottomRight';\n  else if (ySplit > 0) activePane = 'bottomLeft';\n  else activePane = 'topRight';\n  const pane: Pane = {\n    state: 'frozen',\n    topLeftCell: topLeftRef,\n    activePane,\n  };\n  if (xSplit > 0) pane.xSplit = xSplit;\n  if (ySplit > 0) pane.ySplit = ySplit;\n  return pane;\n}\n\n/** Inverse of {@link makeFreezePane}. Returns the top-left ref of the bottomRight pane, or undefined. */\nexport function freezePaneRef(view: SheetView): string | undefined {\n  const pane = view.pane;\n  if (!pane || pane.state !== 'frozen') return undefined;\n  if (pane.topLeftCell) return pane.topLeftCell;\n  const xSplit = pane.xSplit ?? 0;\n  const ySplit = pane.ySplit ?? 0;\n  return tupleToCoordinate(xSplit + 1, ySplit + 1);\n}\n","// Legacy comments.\n//\n// Legacy comments live in `xl/commentsN.xml` (typed comment list + authors\n// index) plus a VML drawing part for the popup balloon shape. Stage-1 covers\n// plain-text comments + author dedup; rich-text + VML shape preservation are\n// reserved for later iterations (we emit a minimal placeholder VML so Excel can\n// re-render).\n\nexport interface LegacyComment {\n  /** Cell reference — typically a single cell (\"A1\") but Excel allows ranges. */\n  ref: string;\n  /** Display name of the comment author. */\n  author: string;\n  /** Plain-text body. Stage-1 doesn't preserve rich-text formatting. */\n  text: string;\n}\n\nexport function makeLegacyComment(opts: { ref: string; author: string; text: string }): LegacyComment {\n  return { ref: opts.ref, author: opts.author, text: opts.text };\n}\n","// Worksheet `<sheetPr>` properties. (sheet view 拡張). Mirrors\n// openpyxl/openpyxl/worksheet/properties.py.\n//\n// Promoting sheetPr out of `bodyExtras.beforeSheetData` gives consumers a typed\n// handle for the most common fields (`tabColor`, `codeName`) and for the two\n// child elements that drive Excel's outline / page-setup behaviour. The full\n// set is modeled so a load → save round-trip preserves the element verbatim —\n// niche sync* / transition* attrs included.\n\nimport type { Color } from '../styles/colors';\n\nexport interface OutlineProperties {\n  applyStyles?: boolean;\n  /** \"Summary rows below detail\" — Excel default true. */\n  summaryBelow?: boolean;\n  /** \"Summary columns to right of detail\" — Excel default true. */\n  summaryRight?: boolean;\n  showOutlineSymbols?: boolean;\n}\n\nexport interface PageSetupProperties {\n  autoPageBreaks?: boolean;\n  fitToPage?: boolean;\n}\n\nexport interface SheetProperties {\n  /** VBA codeName for the sheet (\"Sheet1\" by default but localizable). */\n  codeName?: string;\n  enableFormatConditionsCalculation?: boolean;\n  /** Whether the sheet has an active filter set up. */\n  filterMode?: boolean;\n  /** Whether the sheet is published to a SharePoint Excel Services list. */\n  published?: boolean;\n  /** Sync* attrs control multi-sheet scroll synchronisation. */\n  syncHorizontal?: boolean;\n  syncRef?: string;\n  syncVertical?: boolean;\n  /** \"Lotus 1-2-3 transition\" toggles — almost never seen in modern files. */\n  transitionEvaluation?: boolean;\n  transitionEntry?: boolean;\n  /** Tab strip colour for this sheet (the coloured stripe at the bottom). */\n  tabColor?: Color;\n  outlinePr?: OutlineProperties;\n  pageSetUpPr?: PageSetupProperties;\n}\n\nexport const makeSheetProperties = (opts: SheetProperties = {}): SheetProperties => {\n  const out: SheetProperties = {};\n  if (opts.codeName !== undefined) out.codeName = opts.codeName;\n  if (opts.enableFormatConditionsCalculation !== undefined)\n    out.enableFormatConditionsCalculation = opts.enableFormatConditionsCalculation;\n  if (opts.filterMode !== undefined) out.filterMode = opts.filterMode;\n  if (opts.published !== undefined) out.published = opts.published;\n  if (opts.syncHorizontal !== undefined) out.syncHorizontal = opts.syncHorizontal;\n  if (opts.syncRef !== undefined) out.syncRef = opts.syncRef;\n  if (opts.syncVertical !== undefined) out.syncVertical = opts.syncVertical;\n  if (opts.transitionEvaluation !== undefined) out.transitionEvaluation = opts.transitionEvaluation;\n  if (opts.transitionEntry !== undefined) out.transitionEntry = opts.transitionEntry;\n  if (opts.tabColor !== undefined) out.tabColor = opts.tabColor;\n  if (opts.outlinePr !== undefined) out.outlinePr = opts.outlinePr;\n  if (opts.pageSetUpPr !== undefined) out.pageSetUpPr = opts.pageSetUpPr;\n  return out;\n};\n","// Worksheet data model.\n//\n// Cells live in a sparse two-level Map (row → col → Cell). The choice is\n// deliberate: a workbook with 1 M cells in 1 column shouldn't allocate 1 M\n// empty rows, and JSON.stringify with `Map` round-trips cleanly via the\n// workbook's `jsonReplacer`. Worksheets are mutable for hot-path performance.\n\nimport type { CellValue } from '../cell/cell';\nimport { type Cell, cellValueAsString, makeCell, setArrayFormula, setFormula } from '../cell/cell';\nimport { type InlineFont, makeRichText, type TextRun } from '../cell/rich-text';\nimport type { Drawing } from '../drawing/drawing';\nimport { type Color, makeColor } from '../styles/colors';\nimport {\n  columnIndexFromLetter,\n  columnLetterFromIndex,\n  coordinateToTuple,\n  formatSheetQualifiedRef,\n  MAX_COL,\n  MAX_ROW,\n  tupleToCoordinate,\n} from '../utils/coordinate';\nimport { OpenXmlSchemaError } from '../utils/exceptions';\nimport type { AutoFilter } from './auto-filter';\nimport { type CellRange, parseRange, rangeContainsCell, rangesOverlap, rangeToString } from './cell-range';\nimport type { LegacyComment } from './comments';\nimport { makeLegacyComment } from './comments';\nimport type { ConditionalFormatting } from './conditional-formatting';\nimport type { DataValidation } from './data-validations';\nimport { type ColumnDimension, makeColumnDimension, makeRowDimension, type RowDimension } from './dimensions';\nimport type { DataConsolidate } from './data-consolidate';\nimport type { ScenarioList } from './scenarios';\nimport type { CellWatch, IgnoredError } from './errors';\nimport type { HeaderFooter, PageBreak, PageMargins, PageSetup, PrintOptions } from './page-setup';\nimport type { WorksheetPhoneticProperties } from './phonetic';\nimport { makeSheetProperties, type SheetProperties } from './properties';\nimport type { SheetProtection } from './protection';\nimport type { ProtectedRange } from './protected-ranges';\nimport type { SortState } from './sort-state';\nimport type { WebPublishItem, WorksheetCustomProperty } from './web-publish';\nimport { type Hyperlink, makeHyperlink } from './hyperlinks';\nimport type { TableDefinition } from './table';\nimport { freezePaneRef, makeFreezePane, makeSheetView, type SheetView } from './views';\n\nexport interface Worksheet {\n  title: string;\n  /** Sparse store: row index → (col index → Cell). */\n  rows: Map<number, Map<number, Cell>>;\n  /**\n   * Highest row index touched by `appendRow`; used to keep appendRow O(1)\n   * without re-scanning the row map. Direct setCell / deleteCell may move the\n   * actual maximum elsewhere.\n   */\n  _appendRowCursor: number;\n  /**\n   * Merged cell ranges. The top-left cell holds the value; the rest are mostly\n   * invisible to Excel until unmerge restores them. We persist the list as\n   * plain CellRange[] so mergeCells / unmergeCells can mutate it without\n   * rebuilding any helper structures.\n   */\n  mergedCells: CellRange[];\n  /**\n   * Per-bookView display settings. Most workbooks have exactly one view. The\n   * list stays empty until something — read or API — populates it; a lone\n   * default view doesn't earn its keep on the wire.\n   */\n  views: SheetView[];\n  /**\n   * Per-column metadata keyed by the entry's `min` index. The value's\n   * `min`/`max` may cover a multi-column run; iteration over the map yields one\n   * entry per run, in `min`-ascending order.\n   */\n  columnDimensions: Map<number, ColumnDimension>;\n  /** Per-row metadata keyed by 1-based row index. */\n  rowDimensions: Map<number, RowDimension>;\n  /** Default column width (characters) when not overridden by a column dimension. */\n  defaultColumnWidth?: number;\n  /** Default row height (points) when not overridden by a row dimension. */\n  defaultRowHeight?: number;\n  /**\n   * Highest outline depth used among `rowDimensions`. Excel uses this to size\n   * the outline button strip on the left of the row numbers. Auto-computed by\n   * the writer when undefined — set explicitly to override.\n   */\n  outlineLevelRow?: number;\n  /** Highest outline depth used among `columnDimensions`. Auto-computed by the writer when undefined. */\n  outlineLevelCol?: number;\n  /** \"Custom row heights present\" hint — Excel uses this to skip default-height rendering. */\n  customHeight?: boolean;\n  /** \"Show rows of zero height as one row\" — for hidden rows the outline collapse uses this. */\n  zeroHeight?: boolean;\n  /** Apply a thick top border to every row by default. */\n  thickTop?: boolean;\n  /** Apply a thick bottom border to every row by default. */\n  thickBottom?: boolean;\n  /** Excel's \"base column width\" (characters) — defaults to 8 when unset. */\n  baseColWidth?: number;\n  /** Hyperlinks. External URLs round-trip via worksheet rels; internal jumps stay inline. */\n  hyperlinks: Hyperlink[];\n  /** Data validation entries. */\n  dataValidations: DataValidation[];\n  /** AutoFilter — at most one per sheet. Excel reuses the `_xlnm._FilterDatabase` defined name. */\n  autoFilter?: AutoFilter;\n  /** Excel Table objects. Each lives in its own xl/tables/tableN.xml part. */\n  tables: TableDefinition[];\n  /** Legacy comments. Persisted as `xl/commentsN.xml` + a placeholder VML drawing. */\n  legacyComments: LegacyComment[];\n  /** Conditional formatting blocks. */\n  conditionalFormatting: ConditionalFormatting[];\n  /**\n   * `<sheetPr>` properties — VBA codeName, tab strip color, outline /\n   * page-setup defaults, etc. Top-level `<sheetPr>` lives just before\n   * `<dimension>` per ECMA-376 ordering.\n   */\n  sheetProperties?: SheetProperties;\n  /**\n   * Sheet-protection state. When `sheet=true` Excel locks the sheet against\n   * edits (subject to the per-action allow flags here). Password hashing\n   * helpers come later — for now `saltValue` / `spinCount` / `algorithmName` /\n   * `hashValue` round-trip verbatim.\n   */\n  sheetProtection?: SheetProtection;\n  /**\n   * `<protectedRanges>` — per-range edit-allowance overrides used when the\n   * sheet is otherwise protected (Review → Allow Edit Ranges).\n   */\n  protectedRanges: ProtectedRange[];\n  /**\n   * `<sortState>` — last-applied sort criteria. Excel persists this so the rows\n   * come back in the same order after a save/load cycle.\n   */\n  sortState?: SortState;\n  /**\n   * `<picture r:id=\"…\"/>` — sheet background image (Page Layout → Background).\n   * The rId points at a media part registered in the worksheet rels (preserved\n   * via the existing relsExtras machinery).\n   */\n  backgroundPictureRId?: string;\n  /**\n   * `<legacyDrawingHF r:id=\"…\"/>` — VML drawing used for header/footer\n   * background images on print. Parallel to legacyDrawing (which carries\n   * comment markers); the rels link rides relsExtras.\n   */\n  legacyDrawingHFRId?: string;\n  /**\n   * `<smartTags>` — per-cell smart-tag annotations (Excel 2003 era). Pairs with\n   * the workbook-level smartTagTypes registry.\n   */\n  smartTags: import('./smart-tags').CellSmartTags[];\n  /**\n   * `<customSheetViews>` — saved per-user view presets for this worksheet\n   * (Excel's \"Custom Views\" feature). Each entry snapshots zoom / gridline /\n   * formula / heading toggles plus its own page-setup block and break list.\n   */\n  customSheetViews: import('./custom-sheet-views').CustomSheetView[];\n  /**\n   * `<oleObjects>` — embedded OLE objects (linked Word documents, Equation\n   * editor formulas, etc.). The objectPr child is round-tripped verbatim as an\n   * XmlNode.\n   */\n  oleObjects: import('./ole-objects').OleObject[];\n  /**\n   * `<controls>` — form controls (checkboxes / list boxes / spin buttons placed\n   * via the Developer tab). The controlPr child is round-tripped verbatim.\n   */\n  controls: import('./ole-objects').FormControl[];\n  /** `<printOptions>` — gridlines, headings, horizontal/vertical centering on the printed page. */\n  printOptions?: PrintOptions;\n  /** `<pageMargins>` — six required margins in inches. */\n  pageMargins?: PageMargins;\n  /** `<pageSetup>` — paper size / orientation / scale / fitToPage / DPI etc. */\n  pageSetup?: PageSetup;\n  /** `<headerFooter>` — odd/even/first header + footer mini-format strings + flags. */\n  headerFooter?: HeaderFooter;\n  /** Manual horizontal page breaks (`<rowBreaks>`). Each entry's `id` is the row above which a new page begins. */\n  rowBreaks: PageBreak[];\n  /** Manual vertical page breaks (`<colBreaks>`). Each entry's `id` is the column to the left of which a new page begins. */\n  colBreaks: PageBreak[];\n  /**\n   * Worksheet-level `<customProperties>` — per-sheet user metadata that\n   * SharePoint workflows attach (separate from the workbook-level\n   * `docProps/custom.xml` part). The `rId` points at a Custom XML part\n   * registered in the worksheet rels (already preserved via `relsExtras`).\n   */\n  customProperties: WorksheetCustomProperty[];\n  /** `<webPublishItems>` — Excel 2007's \"Publish to web\" entries. Almost always empty in modern files. */\n  webPublishItems: WebPublishItem[];\n  /**\n   * `<phoneticPr>` — East-Asian furigana rendering hints (font index + IME\n   * conversion mode + alignment). Common in Japanese workbooks.\n   */\n  phoneticPr?: WorksheetPhoneticProperties;\n  /**\n   * `<dataConsolidate>` — config for Data → Consolidate. Carries the\n   * aggregation function and the source-range list.\n   */\n  dataConsolidate?: DataConsolidate;\n  /** `<scenarios>` — the Scenario Manager's saved input-cell overrides. */\n  scenarios?: ScenarioList;\n  /** Cells pinned in Excel's Watch Window (`<cellWatches><cellWatch r=\"…\"/></cellWatches>`). */\n  cellWatches: CellWatch[];\n  /**\n   * Per-region \"ignore this error class\" rules (`<ignoredErrors>`). Suppresses\n   * the small green-triangle warning for the listed checks.\n   */\n  ignoredErrors: IgnoredError[];\n  /**\n   * Spreadsheet drawing — at most one per worksheet. Hosts charts / pictures /\n   * shapes. Persisted as `xl/drawings/drawingN.xml` plus a worksheet-rels\n   * entry; on the wire the worksheet body emits `<drawing r:id>`.\n   */\n  drawing?: Drawing;\n  /**\n   * Per-sheet rels entries we don't model (pivotTable / queryTable / slicer /\n   * printerSettings / customProperty / oleObject etc.). Re-emitted verbatim so\n   * Excel still resolves the captured passthrough parts after a round-trip.\n   */\n  relsExtras?: ReadonlyArray<{ id: string; type: string; target: string }>;\n  /**\n   * Top-level `<worksheet>` children we don't model — `<sheetPr>`,\n   * `<printOptions>`, `<pageMargins>`, `<pageSetup>`, `<headerFooter>`,\n   * `<rowBreaks>`, `<colBreaks>`, `<oleObjects>`, `<controls>`, `<picture>`,\n   * `<extLst>`, etc. Captured as XmlNodes; the writer emits them in two\n   * anchored slots so common ECMA-376 ordering survives a round-trip even\n   * though we don't track every position individually:\n   * - `beforeSheetData` → emitted before our `<dimension>` (typical for\n   * `<sheetPr>`).\n   * - `afterSheetData` → emitted between our `<hyperlinks>` and\n   * `<drawing>` block, which lands page setup / extLst / oleObjects in roughly\n   * the right place. Excel reads back regardless of strict ECMA position;\n   * openpyxl-emitted files round-trip cleanly.\n   */\n  bodyExtras?: {\n    beforeSheetData: import('../xml/tree').XmlNode[];\n    afterSheetData: import('../xml/tree').XmlNode[];\n  };\n}\n\n/** Build a Worksheet shell. */\nexport function makeWorksheet(title: string): Worksheet {\n  if (typeof title !== 'string' || title.length === 0) {\n    throw new OpenXmlSchemaError('Worksheet title must be a non-empty string');\n  }\n  return {\n    title,\n    rows: new Map(),\n    _appendRowCursor: 0,\n    mergedCells: [],\n    views: [],\n    columnDimensions: new Map(),\n    rowDimensions: new Map(),\n    hyperlinks: [],\n    dataValidations: [],\n    tables: [],\n    legacyComments: [],\n    conditionalFormatting: [],\n    cellWatches: [],\n    ignoredErrors: [],\n    rowBreaks: [],\n    colBreaks: [],\n    customProperties: [],\n    webPublishItems: [],\n    protectedRanges: [],\n    smartTags: [],\n    customSheetViews: [],\n    oleObjects: [],\n    controls: [],\n  };\n}\n\nconst validateRowCol = (row: number, col: number): void => {\n  if (!Number.isInteger(row) || row < 1 || row > MAX_ROW) {\n    throw new OpenXmlSchemaError(`Worksheet row ${row} out of range [1, ${MAX_ROW}]`);\n  }\n  if (!Number.isInteger(col) || col < 1 || col > MAX_COL) {\n    throw new OpenXmlSchemaError(`Worksheet col ${col} out of range [1, ${MAX_COL}]`);\n  }\n};\n\n/** Resolve a 1-based or \"A1\" coordinate; returns the populated Cell or undefined. */\nexport function getCell(ws: Worksheet, row: number, col: number): Cell | undefined {\n  return ws.rows.get(row)?.get(col);\n}\n\n/**\n * Create or update a Cell at (row, col). Existing cells keep their styleId /\n * hyperlinkId / commentId unless explicitly overridden.\n */\nexport function setCell(ws: Worksheet, row: number, col: number, value: CellValue = null, styleId?: number): Cell {\n  let rowMap = ws.rows.get(row);\n  let cell = rowMap?.get(col);\n  if (cell === undefined) {\n    // makeCell validates (row, col); no need for a second worksheet-level\n    // validateRowCol on the hot path.\n    cell = makeCell(row, col, value, styleId ?? 0);\n    if (rowMap === undefined) {\n      rowMap = new Map<number, Cell>();\n      ws.rows.set(row, rowMap);\n    }\n    rowMap.set(col, cell);\n  } else {\n    cell.value = value;\n    if (styleId !== undefined) cell.styleId = styleId;\n  }\n  if (row > ws._appendRowCursor) ws._appendRowCursor = row;\n  return cell;\n}\n\n/** Delete a single cell from the sheet. Empty rows are pruned. */\nexport function deleteCell(ws: Worksheet, row: number, col: number): void {\n  const rowMap = ws.rows.get(row);\n  if (rowMap === undefined) return;\n  rowMap.delete(col);\n  if (rowMap.size === 0) ws.rows.delete(row);\n}\n\n/**\n * Delete every populated cell inside a range. Returns the number of cells\n * removed. Row maps that go empty are pruned. Column / row dimensions, merges,\n * comments etc. are left untouched.\n */\nexport function clearRange(ws: Worksheet, range: string): number {\n  const { minRow, maxRow, minCol, maxCol } = parseRange(range);\n  let n = 0;\n  for (let r = minRow; r <= maxRow; r++) {\n    const rowMap = ws.rows.get(r);\n    if (!rowMap) continue;\n    for (let c = minCol; c <= maxCol; c++) {\n      if (rowMap.delete(c)) n++;\n    }\n    if (rowMap.size === 0) ws.rows.delete(r);\n  }\n  return n;\n}\n\n/**\n * Wipe every populated cell on the worksheet, leaving styles, dimensions,\n * merges, comments, hyperlinks etc. intact. Returns the count of cells removed.\n * Useful when a sheet should be re-filled from scratch but its formatting kept.\n */\nexport function clearAllCells(ws: Worksheet): number {\n  let n = 0;\n  for (const rowMap of ws.rows.values()) n += rowMap.size;\n  ws.rows.clear();\n  ws._appendRowCursor = 0;\n  return n;\n}\n\n/**\n * Append a row of values starting at the next empty row. Returns the row index\n * (1-based). Mirrors openpyxl's `Worksheet.append`. `null` / `undefined`\n * entries leave the cell empty.\n */\nexport function appendRow(ws: Worksheet, values: ReadonlyArray<CellValue | undefined>): number {\n  const row = ws._appendRowCursor + 1;\n  for (let i = 0; i < values.length; i++) {\n    const value = values[i];\n    if (value === undefined || value === null) continue;\n    setCell(ws, row, i + 1, value);\n  }\n  // Even if every value is empty, advance the cursor so the next call doesn't\n  // overwrite this row's would-be position.\n  ws._appendRowCursor = row;\n  return row;\n}\n\n/**\n * Bulk version of {@link appendRow}: append a 2D array of values one row at a\n * time. Returns `{firstRow, lastRow}` — both 1-based, inclusive. An empty input\n * returns `{firstRow, lastRow: firstRow - 1}` so callers can detect the no-op\n * without throwing.\n *\n * Common usage: `appendRows(ws, csvParsedRows)` for fast import.\n */\nexport function appendRows(\n  ws: Worksheet,\n  rows: ReadonlyArray<ReadonlyArray<CellValue | undefined>>,\n): { firstRow: number; lastRow: number } {\n  const firstRow = ws._appendRowCursor + 1;\n  if (rows.length === 0) {\n    return { firstRow, lastRow: firstRow - 1 };\n  }\n  let lastRow = firstRow - 1;\n  for (const row of rows) {\n    lastRow = appendRow(ws, row);\n  }\n  return { firstRow, lastRow };\n}\n\n/**\n * Write a 2D array of values to the sheet starting at the given A1 anchor cell.\n * Distinct from {@link appendRows} (which always writes past\n * `_appendRowCursor`) — this lets you place a block at an arbitrary location,\n * e.g. mid-sheet table updates.\n *\n * `null` / `undefined` entries leave the corresponding cell **untouched**\n * (existing cell + style are preserved). Pre-existing cells inside the written\n * rectangle are overwritten in place, so their `styleId` survives the write.\n *\n * Returns the bounding-box of the written area as 1-based inclusive\n * coordinates. An empty rows array returns `undefined` rather than an invalid\n * zero-area range.\n */\nexport function writeRange(\n  ws: Worksheet,\n  startRef: string,\n  values: ReadonlyArray<ReadonlyArray<CellValue | undefined>>,\n): { minRow: number; maxRow: number; minCol: number; maxCol: number } | undefined {\n  if (values.length === 0) return undefined;\n  const { col: startCol, row: startRow } = coordinateToTuple(startRef);\n  let maxRow = startRow;\n  let maxCol = startCol;\n  for (let i = 0; i < values.length; i++) {\n    const row = values[i];\n    if (row === undefined) continue;\n    const r = startRow + i;\n    for (let j = 0; j < row.length; j++) {\n      const v = row[j];\n      if (v === undefined || v === null) continue;\n      const c = startCol + j;\n      setCell(ws, r, c, v);\n      if (c > maxCol) maxCol = c;\n    }\n    if (r > maxRow) maxRow = r;\n  }\n  return { minRow: startRow, maxRow, minCol: startCol, maxCol };\n}\n\nexport interface IterRowsOptions {\n  minRow?: number;\n  maxRow?: number;\n  minCol?: number;\n  maxCol?: number;\n}\n\n/**\n * Iterate the worksheet rows rectangularly. Yields one row per row in\n * `[minRow, maxRow]` — including entirely empty rows — and each yielded row\n * has length `maxCol - minCol + 1`. Missing cell positions are `undefined`\n * (no placeholder Cell allocations).\n *\n * Defaults: `minRow=1`, `maxRow=getMaxRow(ws)`, `minCol=1`,\n * `maxCol=getMaxCol(ws)`. The default extent is the populated bounding box,\n * not the 1M × 16K sheet limit, so the rectangular default doesn't iterate\n * the whole grid for a small sheet.\n *\n * To iterate populated rows only, filter:\n * `[...iterRows(ws)].filter(row => row.some((c) => c !== undefined))`. To\n * iterate populated cells without row boundaries, use {@link iterCells}.\n */\nexport function* iterRows(ws: Worksheet, opts: IterRowsOptions = {}): IterableIterator<(Cell | undefined)[]> {\n  const { minRow = 1, maxRow = getMaxRow(ws), minCol = 1, maxCol = getMaxCol(ws) } = opts;\n  if (maxRow < minRow || maxCol < minCol) return;\n  const width = maxCol - minCol + 1;\n  for (let r = minRow; r <= maxRow; r++) {\n    const rowMap = ws.rows.get(r);\n    // Fill explicitly so the array isn't sparse — `.map` callbacks would skip\n    // empty slots and surprise the caller.\n    const out: (Cell | undefined)[] = new Array(width).fill(undefined);\n    if (rowMap !== undefined) {\n      for (let c = minCol; c <= maxCol; c++) {\n        const cell = rowMap.get(c);\n        if (cell !== undefined) out[c - minCol] = cell;\n      }\n    }\n    yield out;\n  }\n}\n\n/**\n * Same rectangular iteration as {@link iterRows}, but yields each cell's\n * `.value`. Missing cell positions become `null` — already the canonical empty\n * marker in `CellValue`.\n */\nexport function* iterValues(ws: Worksheet, opts: IterRowsOptions = {}): IterableIterator<CellValue[]> {\n  for (const row of iterRows(ws, opts)) {\n    yield row.map((c) => (c === undefined ? null : c.value));\n  }\n}\n\n/**\n * Yield every populated cell in the worksheet as a flat stream (row-major,\n * columns ascending). Distinct from {@link iterRows} which yields one row\n * per row in the bounding box — use this when the caller wants only the\n * populated cells without row boundaries or rectangular padding.\n */\nexport function* iterCells(ws: Worksheet, opts: IterRowsOptions = {}): IterableIterator<Cell> {\n  for (const row of iterRows(ws, opts)) {\n    for (const cell of row) {\n      if (cell !== undefined) yield cell;\n    }\n  }\n}\n\n/** Effective max row index based on populated cells (0 when empty). */\nexport function getMaxRow(ws: Worksheet): number {\n  let m = 0;\n  for (const r of ws.rows.keys()) if (r > m) m = r;\n  return m;\n}\n\n/** Effective max column index based on populated cells (0 when empty). */\nexport function getMaxCol(ws: Worksheet): number {\n  let m = 0;\n  for (const rowMap of ws.rows.values()) {\n    for (const c of rowMap.keys()) if (c > m) m = c;\n  }\n  return m;\n}\n\n/**\n * Sorted list of every row index that holds at least one populated cell.\n * Returns `[]` for an empty worksheet. Useful when a caller wants to iterate\n * only the rows the user actually populated, without walking 1..maxRow in dense\n * fashion.\n */\nexport function getPopulatedRowIndices(ws: Worksheet): number[] {\n  const out: number[] = [];\n  for (const [r, rowMap] of ws.rows) {\n    if (rowMap.size > 0) out.push(r);\n  }\n  return out.sort((a, b) => a - b);\n}\n\n/**\n * Sorted list of every column index that holds at least one populated cell\n * anywhere on the sheet. Distinct columns only; returns `[]` for an empty\n * worksheet.\n */\nexport function getPopulatedColumnIndices(ws: Worksheet): number[] {\n  const seen = new Set<number>();\n  for (const rowMap of ws.rows.values()) {\n    for (const c of rowMap.keys()) seen.add(c);\n  }\n  return [...seen].sort((a, b) => a - b);\n}\n\n/**\n * Tally populated cells by value kind. Useful for stats / debugging dashboards\n * that want a quick \"this sheet has N strings, M formulas, K dates\" snapshot.\n *\n * Buckets:\n *   - `null`: empty cells (cell exists but value is null)\n *   - `string`: plain strings\n *   - `number`: numeric primitives\n *   - `boolean`: TRUE / FALSE\n *   - `date`: native `Date` instances\n *   - `duration`: `{ kind: 'duration', ms }` values\n *   - `error`: `#REF!` / `#VALUE!` / etc. error values\n *   - `rich-text`: `{ kind: 'rich-text', runs }` values\n *   - `formula`: `FormulaValue` (regardless of cached value type)\n */\nexport interface CellsByKindCounts {\n  null: number;\n  string: number;\n  number: number;\n  boolean: number;\n  date: number;\n  duration: number;\n  error: number;\n  'rich-text': number;\n  formula: number;\n}\n\n/**\n * Bucket a single CellValue into one of the {@link CellsByKindCounts} keys.\n * Shared between {@link countCellsByKind} and the workbook-wide overview so\n * the two never drift in how they classify (e.g. `Date` vs `duration`).\n */\nexport function classifyCellValue(v: import('../cell/cell').CellValue): keyof CellsByKindCounts {\n  if (v === null) return 'null';\n  if (typeof v === 'string') return 'string';\n  if (typeof v === 'number') return 'number';\n  if (typeof v === 'boolean') return 'boolean';\n  if (v instanceof Date) return 'date';\n  const kind = (v as { kind?: string }).kind;\n  if (kind === 'duration') return 'duration';\n  if (kind === 'error') return 'error';\n  if (kind === 'rich-text') return 'rich-text';\n  // Remaining shape is FormulaValue (kind === 'formula').\n  return 'formula';\n}\n\nexport function countCellsByKind(ws: Worksheet): CellsByKindCounts {\n  const out: CellsByKindCounts = {\n    null: 0,\n    string: 0,\n    number: 0,\n    boolean: 0,\n    date: 0,\n    duration: 0,\n    error: 0,\n    'rich-text': 0,\n    formula: 0,\n  };\n  for (const cell of iterCells(ws)) {\n    out[classifyCellValue(cell.value)]++;\n  }\n  return out;\n}\n\n/**\n * Sheet-qualified A1 address for a cell — `'Sheet1!A1'` for plain titles,\n * `'\\'Quarter 1\\'!A1'` for titles needing quoting (spaces, apostrophes,\n * punctuation, leading-digit). Round-trips with {@link parseSheetRange}.\n *\n * Useful when constructing formulas / defined-names that reference a specific\n * cell across sheets without hand-rolling the quote logic.\n */\nexport function getCellAddress(ws: Worksheet, c: Cell): string {\n  return formatSheetQualifiedRef(ws.title, tupleToCoordinate(c.col, c.row));\n}\n\n/**\n * Sheet-qualified A1 range address — `'Sheet1!A1:B5'` for plain titles,\n * `'\\'Quarter 1\\'!A1:B5'` for titles needing quoting. Pass any A1-style range\n * string (single cell `'A1'`, rectangle `'A1:B5'`, row span `'1:5'`, column\n * span `'A:E'`); the helper does no validation on `range` itself — that's the\n * caller's responsibility.\n */\nexport function getRangeAddress(ws: Worksheet, range: string): string {\n  return formatSheetQualifiedRef(ws.title, range);\n}\n\n/**\n * True iff the worksheet has zero non-empty cells. Equivalent to\n * `getNonEmptyCellCount(ws) === 0` but short-circuits on the first non-null\n * value found, so the cost is O(first non-empty cell) rather than O(populated\n * cells).\n */\nexport function isWorksheetEmpty(ws: Worksheet): boolean {\n  for (const cell of iterCells(ws)) {\n    if (cell.value !== null) return false;\n  }\n  return true;\n}\n\n/**\n * Count non-empty cells. Distinct from {@link countCells} which counts every\n * materialised cell (including ones whose `value === null`): this skips cells\n * with a `null` value, plus optionally formulas / rich-text per the opts.\n *\n * Useful for \"how many real values does this sheet contain\" stats vs the\n * materialised footprint.\n */\nexport function getNonEmptyCellCount(\n  ws: Worksheet,\n  opts: { includeFormulas?: boolean; includeRichText?: boolean } = {},\n): number {\n  const includeFormulas = opts.includeFormulas ?? true;\n  const includeRichText = opts.includeRichText ?? true;\n  let n = 0;\n  for (const cell of iterCells(ws)) {\n    const v = cell.value;\n    if (v === null) continue;\n    if (typeof v === 'object' && v !== null) {\n      const kind = (v as { kind?: string }).kind;\n      if (kind === 'formula' && !includeFormulas) continue;\n      if (kind === 'rich-text' && !includeRichText) continue;\n    }\n    n++;\n  }\n  return n;\n}\n\n/** Total populated cell count. */\nexport function countCells(ws: Worksheet): number {\n  let n = 0;\n  for (const rowMap of ws.rows.values()) n += rowMap.size;\n  return n;\n}\n\n/**\n * Bounding-box of the populated cells: `{ minRow, maxRow, minCol, maxCol }`\n * covering every cell in `ws.rows`. Returns `undefined` when the sheet is\n * empty. Walks the sparse store once.\n */\nexport function getDataExtent(\n  ws: Worksheet,\n): { minRow: number; maxRow: number; minCol: number; maxCol: number } | undefined {\n  let minRow = Number.POSITIVE_INFINITY;\n  let maxRow = 0;\n  let minCol = Number.POSITIVE_INFINITY;\n  let maxCol = 0;\n  let touched = false;\n  for (const [r, rowMap] of ws.rows) {\n    if (rowMap.size === 0) continue;\n    if (r < minRow) minRow = r;\n    if (r > maxRow) maxRow = r;\n    for (const c of rowMap.keys()) {\n      if (c < minCol) minCol = c;\n      if (c > maxCol) maxCol = c;\n    }\n    touched = true;\n  }\n  if (!touched) return undefined;\n  return { minRow, maxRow, minCol, maxCol };\n}\n\n/**\n * Same as {@link getDataExtent} but returns the canonical `\"A1:E10\"` range\n * string for the bounding box, or `undefined` when the sheet is empty.\n */\nexport function getDataExtentRef(ws: Worksheet): string | undefined {\n  const ext = getDataExtent(ws);\n  if (!ext) return undefined;\n  return rangeToString({\n    minRow: ext.minRow,\n    maxRow: ext.maxRow,\n    minCol: ext.minCol,\n    maxCol: ext.maxCol,\n  });\n}\n\n/**\n * Iterate every populated cell, yielding those for which `predicate` returns\n * true. Iteration order is row-then-column ascending. Cells whose `.value ===\n * null` (empty placeholders carrying only style or comment metadata) are still\n * visited.\n */\nexport function* findCells(\n  ws: Worksheet,\n  predicate: (c: Cell) => boolean,\n): IterableIterator<Cell> {\n  const rowKeys = [...ws.rows.keys()].sort((a, b) => a - b);\n  for (const r of rowKeys) {\n    const rowMap = ws.rows.get(r);\n    if (!rowMap) continue;\n    const cols = [...rowMap.keys()].sort((a, b) => a - b);\n    for (const c of cols) {\n      const cell = rowMap.get(c);\n      if (cell !== undefined && predicate(cell)) yield cell;\n    }\n  }\n}\n\n/** First populated cell satisfying `predicate`, or `undefined`. */\nexport function findFirstCell(\n  ws: Worksheet,\n  predicate: (c: Cell) => boolean,\n): Cell | undefined {\n  for (const cell of findCells(ws, predicate)) return cell;\n  return undefined;\n}\n\n/**\n * Find-and-replace across populated string cells. `search` matches either an\n * exact-string equal (when given a string) or every cell whose value satisfies\n * the predicate (when given a function). `replacement` is the new value for\n * each match. Returns the count of cells changed. Non-string-valued cells are\n * skipped when `search` is a string; predicate-based searches see every cell.\n */\nexport function replaceCellValues(\n  ws: Worksheet,\n  search: string | ((value: CellValue, cell: Cell) => boolean),\n  replacement: CellValue,\n): number {\n  let n = 0;\n  const matchFn =\n    typeof search === 'string'\n      ? (v: CellValue) => typeof v === 'string' && v === search\n      : (v: CellValue, c: Cell) => search(v, c);\n  for (const rowMap of ws.rows.values()) {\n    for (const cell of rowMap.values()) {\n      if (matchFn(cell.value, cell)) {\n        cell.value = replacement;\n        n++;\n      }\n    }\n  }\n  return n;\n}\n\n/**\n * Range-scoped find-and-replace. Same matching rules as {@link\n * replaceCellValues} (string → exact-equal on string-valued cells; function →\n * predicate over every populated cell), but only cells inside the rectangular\n * `range` are visited. Returns the count changed.\n */\nexport function replaceInRange(\n  ws: Worksheet,\n  range: string,\n  search: string | ((value: CellValue, cell: Cell) => boolean),\n  replacement: CellValue,\n): number {\n  let n = 0;\n  const matchFn =\n    typeof search === 'string'\n      ? (v: CellValue) => typeof v === 'string' && v === search\n      : (v: CellValue, c: Cell) => search(v, c);\n  for (const cell of getCellsInRange(ws, range)) {\n    if (matchFn(cell.value, cell)) {\n      cell.value = replacement;\n      n++;\n    }\n  }\n  return n;\n}\n\n/**\n * Iterate the populated cells inside a rectangular range. Cells that don't\n * exist in the sparse store are skipped (no auto-allocate). Use {@link\n * applyToRange} when you need every coordinate visited regardless of\n * population.\n */\nexport function* getCellsInRange(ws: Worksheet, range: string): IterableIterator<Cell> {\n  const { minRow, maxRow, minCol, maxCol } = parseRange(range);\n  for (let r = minRow; r <= maxRow; r++) {\n    const rowMap = ws.rows.get(r);\n    if (!rowMap) continue;\n    for (let col = minCol; col <= maxCol; col++) {\n      const cell = rowMap.get(col);\n      if (cell !== undefined) yield cell;\n    }\n  }\n}\n\n/**\n * Set a cell's value to a rich-text run array. Accepts either a pre-built\n * `RichText` (frozen array of TextRun) or a fresh `Array<{ text, font? }>`\n * shape — `makeRichText` normalises and freezes the runs in either case.\n * Returns the cell.\n */\nexport function setCellRichText(\n  ws: Worksheet,\n  row: number,\n  col: number,\n  runs: ReadonlyArray<TextRun | { text: string; font?: InlineFont }>,\n  styleId?: number,\n): Cell {\n  return setCell(ws, row, col, { kind: 'rich-text', runs: makeRichText(runs) }, styleId);\n}\n\n/**\n * Set a cell's value to a normal Excel formula. Combines `setCell` with\n * `setFormula`. The leading `=` is stripped if present so callers can pass\n * `'=A1+1'` or `'A1+1'` interchangeably.\n */\nexport function setCellFormula(\n  ws: Worksheet,\n  row: number,\n  col: number,\n  formula: string,\n  opts?: { cachedValue?: number | string | boolean; styleId?: number },\n): Cell {\n  const expr = formula.startsWith('=') ? formula.slice(1) : formula;\n  const cell = setCell(ws, row, col, undefined, opts?.styleId);\n  setFormula(cell, expr, opts?.cachedValue !== undefined ? { cachedValue: opts.cachedValue } : undefined);\n  return cell;\n}\n\n/**\n * Set a cell's value to an array (CSE) formula spanning `ref`. Lands the\n * formula on the top-left cell of the range — Excel reads the `ref` attribute\n * to know how far the result spreads. Equivalent to `setCell` +\n * `setArrayFormula`. Leading `=` is stripped.\n */\nexport function setCellArrayFormula(\n  ws: Worksheet,\n  row: number,\n  col: number,\n  ref: string,\n  formula: string,\n  opts?: { cachedValue?: number | string | boolean; styleId?: number },\n): Cell {\n  const expr = formula.startsWith('=') ? formula.slice(1) : formula;\n  const cell = setCell(ws, row, col, undefined, opts?.styleId);\n  setArrayFormula(cell, ref, expr, opts?.cachedValue !== undefined ? { cachedValue: opts.cachedValue } : undefined);\n  return cell;\n}\n\n/** Resolve an \"A1\" coordinate to a numeric (col, row) pair on the sheet. */\nexport function setCellByCoord(ws: Worksheet, coord: string, value?: CellValue, styleId?: number): Cell {\n  const m = /^([A-Za-z]{1,3})([1-9][0-9]*)$/.exec(coord);\n  if (m === null || m[1] === undefined || m[2] === undefined) {\n    throw new OpenXmlSchemaError(`setCellByCoord: invalid coordinate \"${coord}\"`);\n  }\n  const col = columnIndexFromLetter(m[1]);\n  const row = Number.parseInt(m[2], 10);\n  return setCell(ws, row, col, value, styleId);\n}\n\n/** Convenience getter accepting an \"A1\" coordinate. */\nexport function getCellByCoord(ws: Worksheet, coord: string): Cell | undefined {\n  const m = /^([A-Za-z]{1,3})([1-9][0-9]*)$/.exec(coord);\n  if (m === null || m[1] === undefined || m[2] === undefined) return undefined;\n  const col = columnIndexFromLetter(m[1]);\n  const row = Number.parseInt(m[2], 10);\n  return getCell(ws, row, col);\n}\n\n// ---- merged cells ---------------------------------------------------------\n\nconst toCellRange = (refOrRange: string | CellRange): CellRange =>\n  typeof refOrRange === 'string' ? parseRange(refOrRange) : refOrRange;\n\n/**\n * Merge a range. The top-left cell keeps its value; every other cell in the\n * range is dropped from `ws.rows` so the on-wire `<sheetData>` won't carry\n * phantom cells underneath the merge. Mirrors openpyxl's\n * `MergedCellRange.format()`. Idempotent for an identical range, throws when\n * the range overlaps an existing merge.\n */\nexport function mergeCells(ws: Worksheet, refOrRange: string | CellRange): CellRange {\n  const range = toCellRange(refOrRange);\n  for (const existing of ws.mergedCells) {\n    if (rangeToString(existing) === rangeToString(range)) return existing;\n    if (rangesOverlap(existing, range)) {\n      throw new OpenXmlSchemaError(\n        `mergeCells: range ${rangeToString(range)} overlaps existing merged range ${rangeToString(existing)}`,\n      );\n    }\n  }\n  // Drop every cell except the top-left from the sparse store.\n  for (let r = range.minRow; r <= range.maxRow; r++) {\n    for (let c = range.minCol; c <= range.maxCol; c++) {\n      if (r === range.minRow && c === range.minCol) continue;\n      ws.rows.get(r)?.delete(c);\n      const row = ws.rows.get(r);\n      if (row && row.size === 0) ws.rows.delete(r);\n    }\n  }\n  ws.mergedCells.push(range);\n  return range;\n}\n\n/** Drop a previously-merged range. No-op if the range isn't registered. */\nexport function unmergeCells(ws: Worksheet, refOrRange: string | CellRange): boolean {\n  const target = rangeToString(toCellRange(refOrRange));\n  const idx = ws.mergedCells.findIndex((r) => rangeToString(r) === target);\n  if (idx < 0) return false;\n  ws.mergedCells.splice(idx, 1);\n  return true;\n}\n\n/** Read-only iterator over the worksheet's merged ranges. */\nexport function getMergedCells(ws: Worksheet): ReadonlyArray<CellRange> {\n  return ws.mergedCells;\n}\n\n/** True iff (row, col) sits inside any merged range — top-left included. */\nexport function isMergedCell(ws: Worksheet, row: number, col: number): boolean {\n  for (const range of ws.mergedCells) {\n    if (rangeContainsCell(range, row, col)) return true;\n  }\n  return false;\n}\n\n/**\n * Look up the merged range covering (row, col), or `undefined` if the\n * coordinate isn't inside any merge. Lets callers introspect a merge without\n * iterating `getMergedCells` themselves.\n */\nexport function getMergedRangeAt(ws: Worksheet, row: number, col: number): CellRange | undefined {\n  for (const range of ws.mergedCells) {\n    if (rangeContainsCell(range, row, col)) return range;\n  }\n  return undefined;\n}\n\n/**\n * Drop the merge that contains (row, col), if any. Returns `true` when a merge\n * was unregistered. Useful when callers know a cell coordinate but not the\n * original merge bounds.\n */\nexport function unmergeCellsAt(ws: Worksheet, row: number, col: number): boolean {\n  for (let i = 0; i < ws.mergedCells.length; i++) {\n    const r = ws.mergedCells[i];\n    if (r && rangeContainsCell(r, row, col)) {\n      ws.mergedCells.splice(i, 1);\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Drop every merged range on the worksheet. Returns the count of merges\n * removed. Cells that were inside the merges keep their values — only the merge\n * metadata is gone.\n */\nexport function removeAllMergedRanges(ws: Worksheet): number {\n  const n = ws.mergedCells.length;\n  ws.mergedCells = [];\n  return n;\n}\n\n// ---- views / freezePanes --------------------------------------------------\n\n/** Lazily get-or-create the primary SheetView so view-mutating helpers don't have to branch. */\nconst ensurePrimaryView = (ws: Worksheet): SheetView => {\n  let view = ws.views[0];\n  if (!view) {\n    view = makeSheetView();\n    ws.views.push(view);\n  }\n  return view;\n};\n\n/**\n * Freeze rows / columns above + left of `topLeftRef` (\"B2\" → 1 row + 1 col).\n * Pass `undefined` to clear any existing freeze. Targets the workbook's primary\n * SheetView (`ws.views[0]`); creates one if absent.\n */\nexport function setFreezePanes(ws: Worksheet, topLeftRef: string | undefined): void {\n  if (topLeftRef === undefined) {\n    if (ws.views[0]) delete ws.views[0].pane;\n    return;\n  }\n  const view = ensurePrimaryView(ws);\n  view.pane = makeFreezePane(topLeftRef);\n}\n\n/** Inverse of {@link setFreezePanes}; returns the top-left ref or undefined when no freeze is active. */\nexport function getFreezePanes(ws: Worksheet): string | undefined {\n  const view = ws.views[0];\n  if (!view) return undefined;\n  return freezePaneRef(view);\n}\n\n/**\n * Freeze the top `count` rows. Equivalent to `setFreezePanes(ws, \"A${count +\n * 1}\")` — Excel's \"Freeze Top Row\" is `freezeRows(ws, 1)`.\n */\nexport function freezeRows(ws: Worksheet, count: number): void {\n  if (!Number.isInteger(count) || count < 1) {\n    throw new OpenXmlSchemaError(`freezeRows: count must be a positive integer; got ${count}`);\n  }\n  setFreezePanes(ws, `A${count + 1}`);\n}\n\n/**\n * Freeze the leftmost `count` columns. Equivalent to `setFreezePanes(ws,\n * \"${columnLetter(count + 1)}1\")` — Excel's \"Freeze First Column\" is\n * `freezeColumns(ws, 1)`.\n */\nexport function freezeColumns(ws: Worksheet, count: number): void {\n  if (!Number.isInteger(count) || count < 1) {\n    throw new OpenXmlSchemaError(`freezeColumns: count must be a positive integer; got ${count}`);\n  }\n  setFreezePanes(ws, `${columnLetterFromIndex(count + 1)}1`);\n}\n\n/** Freeze both top `rows` rows AND left `cols` columns. */\nexport function freezePanes(ws: Worksheet, rows: number, cols: number): void {\n  if (!Number.isInteger(rows) || rows < 1) {\n    throw new OpenXmlSchemaError(`freezePanes: rows must be a positive integer; got ${rows}`);\n  }\n  if (!Number.isInteger(cols) || cols < 1) {\n    throw new OpenXmlSchemaError(`freezePanes: cols must be a positive integer; got ${cols}`);\n  }\n  setFreezePanes(ws, `${columnLetterFromIndex(cols + 1)}${rows + 1}`);\n}\n\n/** Drop the freeze pane on the primary view. */\nexport const unfreezePanes = (ws: Worksheet): void => {\n  setFreezePanes(ws, undefined);\n};\n\n/**\n * Freeze the header row (row 1) so it stays visible while scrolling. Equivalent\n * to Excel's \"View → Freeze Top Row\". Shortcut for `freezeRows(ws, 1)`.\n */\nexport const freezeFirstRow = (ws: Worksheet): void => freezeRows(ws, 1);\n\n/**\n * Freeze the leftmost column (column A) so it stays visible while scrolling\n * horizontally. Equivalent to Excel's \"View → Freeze First Column\". Shortcut\n * for `freezeColumns(ws, 1)`.\n */\nexport const freezeFirstColumn = (ws: Worksheet): void => freezeColumns(ws, 1);\n\n/**\n * Freeze both row 1 and column A so the header row + label column stay visible.\n * Equivalent to selecting B2 and \"View → Freeze Panes\". Shortcut for\n * `freezePanes(ws, 1, 1)`.\n */\nexport const freezeFirstRowAndColumn = (ws: Worksheet): void => freezePanes(ws, 1, 1);\n\n// ---- sheet view display helpers -------------------------------------------\n\n/** Lazily get-or-create `ws.sheetProperties` so tab-color helpers don't have to branch. */\nconst ensureSheetProperties = (ws: Worksheet): SheetProperties => {\n  if (!ws.sheetProperties) ws.sheetProperties = makeSheetProperties();\n  return ws.sheetProperties;\n};\n\nconst colorFrom = (input: string | Partial<Color>): Color =>\n  typeof input === 'string' ? makeColor({ rgb: input }) : makeColor(input);\n\n/**\n * Set the sheet tab strip colour. Accepts either a hex string (`\"FF0070C0\"`) or\n * a partial `Color` object (`{ theme: 4, tint: 0.4 }`).\n */\nexport function setSheetTabColor(ws: Worksheet, color: string | Partial<Color>): Color {\n  const c = colorFrom(color);\n  ensureSheetProperties(ws).tabColor = c;\n  return c;\n}\n\n/** Drop the sheet tab strip colour. */\nexport function removeSheetTabColor(ws: Worksheet): void {\n  if (!ws.sheetProperties) return;\n  delete (ws.sheetProperties as { tabColor?: Color }).tabColor;\n}\n\n/** Toggle gridline display on the primary SheetView. */\nexport function setShowGridLines(ws: Worksheet, show: boolean): void {\n  ensurePrimaryView(ws).showGridLines = show;\n}\n\n/** Toggle row + column header display on the primary SheetView. */\nexport function setShowRowColHeaders(ws: Worksheet, show: boolean): void {\n  ensurePrimaryView(ws).showRowColHeaders = show;\n}\n\n/** Toggle \"Show Formulas\" mode on the primary SheetView. */\nexport function setShowFormulas(ws: Worksheet, show: boolean): void {\n  ensurePrimaryView(ws).showFormulas = show;\n}\n\n/** Toggle \"Show a zero in cells that have a zero value\" on the primary SheetView. */\nexport function setShowZeros(ws: Worksheet, show: boolean): void {\n  ensurePrimaryView(ws).showZeros = show;\n}\n\n/** Toggle right-to-left layout on the primary SheetView. */\nexport function setRightToLeft(ws: Worksheet, rtl: boolean): void {\n  ensurePrimaryView(ws).rightToLeft = rtl;\n}\n\n/**\n * Set the zoom scale (percent) on the primary SheetView. Excel accepts integer\n * percentages in `[10, 400]`.\n */\nexport function setSheetZoom(ws: Worksheet, scale: number): void {\n  if (!Number.isInteger(scale) || scale < 10 || scale > 400) {\n    throw new OpenXmlSchemaError(`setSheetZoom: scale must be an integer in [10, 400]; got ${scale}`);\n  }\n  ensurePrimaryView(ws).zoomScale = scale;\n}\n\n/** Switch the sheet view between Excel's \"Normal\" / \"Page Break Preview\" / \"Page Layout\" modes. */\nexport function setSheetViewMode(ws: Worksheet, mode: 'normal' | 'pageBreakPreview' | 'pageLayout'): void {\n  ensurePrimaryView(ws).view = mode;\n}\n\n/**\n * Set the active cell on the primary SheetView. The active cell is the one\n * Excel highlights with the dark border when the sheet is opened. Updates the\n * existing Selection; creates one if missing. Pass an \"A1\"-style ref.\n */\nexport function setActiveCell(ws: Worksheet, ref: string): void {\n  const view = ensurePrimaryView(ws);\n  const selection = view.selection ?? {};\n  // Excel typically also sets sqref to the same cell when a single cell is the\n  // active one. Only override sqref if it's missing or tracked the previous\n  // activeCell, so explicit selections survive.\n  const prevActive = selection.activeCell;\n  if (selection.sqref === undefined || selection.sqref === prevActive) {\n    selection.sqref = ref;\n  }\n  selection.activeCell = ref;\n  view.selection = selection;\n}\n\n/**\n * Set the selected range (sqref) on the primary SheetView. Accepts a single\n * cell (\"A1\"), a single range (\"A1:B5\"), or a multi-cell range string (\"A1\n * C3:D4\"). Leaves activeCell untouched unless absent — in which case it's set\n * to the first ref of `sqref`.\n */\nexport function setSelectedRange(ws: Worksheet, sqref: string): void {\n  const view = ensurePrimaryView(ws);\n  const selection = view.selection ?? {};\n  selection.sqref = sqref;\n  if (selection.activeCell === undefined) {\n    const first = sqref.split(/\\s+/)[0]?.split(':')[0];\n    if (first) selection.activeCell = first;\n  }\n  view.selection = selection;\n}\n\n/**\n * Set values across a rectangular range from a 2-D array. `rows[0]` is laid\n * down starting at the top-left of `range`; subsequent rows follow. `null` /\n * `undefined` entries skip the cell. Useful for dropping a header + data block\n * in one call.\n */\nexport function setRangeValues(\n  ws: Worksheet,\n  range: string,\n  rows: ReadonlyArray<ReadonlyArray<CellValue | null | undefined>>,\n): void {\n  const { minRow, minCol } = parseRange(range);\n  for (let i = 0; i < rows.length; i++) {\n    const row = rows[i];\n    if (!row) continue;\n    for (let j = 0; j < row.length; j++) {\n      const v = row[j];\n      if (v === null || v === undefined) continue;\n      setCell(ws, minRow + i, minCol + j, v);\n    }\n  }\n}\n\n/**\n * Iterate over every cell coordinate in a range, calling `visit` once per (row,\n * col). Allocates the cell on first touch so callers can mutate it freely.\n */\nexport function applyToRange(\n  ws: Worksheet,\n  range: string,\n  visit: (cell: Cell, row: number, col: number) => void,\n): void {\n  const { minRow, maxRow, minCol, maxCol } = parseRange(range);\n  for (let r = minRow; r <= maxRow; r++) {\n    for (let c = minCol; c <= maxCol; c++) {\n      let cell = ws.rows.get(r)?.get(c);\n      if (!cell) cell = setCell(ws, r, c);\n      visit(cell, r, c);\n    }\n  }\n}\n\n/**\n * Read a rectangular range as a dense 2-D array of values. Empty cells yield\n * `null`. The shape is `[maxRow - minRow + 1] × [maxCol - minCol + 1]`. Inverse\n * of {@link setRangeValues}.\n */\nexport function getRangeValues(ws: Worksheet, range: string): (CellValue | null)[][] {\n  const { minRow, maxRow, minCol, maxCol } = parseRange(range);\n  const rowsOut: (CellValue | null)[][] = [];\n  for (let r = minRow; r <= maxRow; r++) {\n    const rowMap = ws.rows.get(r);\n    const row: (CellValue | null)[] = [];\n    for (let c = minCol; c <= maxCol; c++) {\n      const cell = rowMap?.get(c);\n      row.push(cell ? cell.value : null);\n    }\n    rowsOut.push(row);\n  }\n  return rowsOut;\n}\n\n/**\n * Copy every populated cell from `source` to `target` (within the same\n * worksheet, or across worksheets via `targetWs`). Cells are shallow-cloned:\n * `value` and `styleId` carry over but `row`/`col` are rewritten. The target's\n * existing cells in the destination extent are overwritten; cells outside are\n * untouched.\n *\n * The source and target ranges define the top-left corner — their dimensions\n * need not match. If the target range is smaller than the source, only the\n * cells that fit within the target's extent are copied; if larger, only the\n * source's extent is filled.\n *\n * Returns the number of cells copied.\n */\nexport function copyRange(\n  ws: Worksheet,\n  source: string,\n  target: string,\n  opts: { targetWs?: Worksheet } = {},\n): number {\n  const dest = opts.targetWs ?? ws;\n  const sameSheet = dest === ws;\n  const src = parseRange(source);\n  const dst = parseRange(target);\n  const dr = dst.minRow - src.minRow;\n  const dc = dst.minCol - src.minCol;\n  const maxRowOffset = Math.min(src.maxRow - src.minRow, dst.maxRow - dst.minRow);\n  const maxColOffset = Math.min(src.maxCol - src.minCol, dst.maxCol - dst.minCol);\n  let n = 0;\n  for (let i = 0; i <= maxRowOffset; i++) {\n    const srcRow = ws.rows.get(src.minRow + i);\n    if (!srcRow) continue;\n    for (let j = 0; j <= maxColOffset; j++) {\n      const srcCell = srcRow.get(src.minCol + j);\n      if (!srcCell) continue;\n      const dstRow = src.minRow + i + dr;\n      const dstCol = src.minCol + j + dc;\n      const newCell = setCell(dest, dstRow, dstCol, srcCell.value, srcCell.styleId);\n      // hyperlinkId / commentId index into the *source* worksheet's\n      // `hyperlinks` / `legacyComments` arrays. Carrying them across sheets\n      // would point at unrelated entries on the destination (or a missing\n      // slot), so we keep them only on a same-sheet copy. The actual link /\n      // comment records aren't part of the copied range — callers needing\n      // cross-sheet link semantics should re-issue setHyperlink on the dest.\n      if (sameSheet) {\n        if (srcCell.hyperlinkId !== undefined) newCell.hyperlinkId = srcCell.hyperlinkId;\n        if (srcCell.commentId !== undefined) newCell.commentId = srcCell.commentId;\n      }\n      n++;\n    }\n  }\n  return n;\n}\n\n/**\n * Move every populated cell from `source` to `target`. Equivalent to\n * `copyRange` followed by clearing the source. When the ranges overlap on the\n * same sheet, the copy walks in the direction that preserves data — high-to-low\n * along any axis where the move shifts forward, low-to-high otherwise — so\n * cells aren't overwritten before they've been read. Returns the number of\n * cells moved.\n */\nexport function moveRange(\n  ws: Worksheet,\n  source: string,\n  target: string,\n  opts: { targetWs?: Worksheet } = {},\n): number {\n  const dest = opts.targetWs ?? ws;\n  const sameSheet = dest === ws;\n  const src = parseRange(source);\n  const dst = parseRange(target);\n  const dr = dst.minRow - src.minRow;\n  const dc = dst.minCol - src.minCol;\n  const maxRowOffset = Math.min(src.maxRow - src.minRow, dst.maxRow - dst.minRow);\n  const maxColOffset = Math.min(src.maxCol - src.minCol, dst.maxCol - dst.minCol);\n  // Snapshot the source cells so overlapping moves on the same sheet don't read\n  // post-write values during the copy.\n  const snap: Array<{ row: number; col: number; cell: Cell }> = [];\n  for (let i = 0; i <= maxRowOffset; i++) {\n    const srcRow = ws.rows.get(src.minRow + i);\n    if (!srcRow) continue;\n    for (let j = 0; j <= maxColOffset; j++) {\n      const srcCell = srcRow.get(src.minCol + j);\n      if (!srcCell) continue;\n      snap.push({ row: src.minRow + i, col: src.minCol + j, cell: srcCell });\n    }\n  }\n  // Clear the entire source band on the source sheet first so the pre-existing\n  // source cells are gone before we land copies on top.\n  for (let i = 0; i <= maxRowOffset; i++) {\n    const rowIdx = src.minRow + i;\n    const srcRow = ws.rows.get(rowIdx);\n    if (!srcRow) continue;\n    for (let j = 0; j <= maxColOffset; j++) srcRow.delete(src.minCol + j);\n    if (srcRow.size === 0) ws.rows.delete(rowIdx);\n  }\n  // Replay the snapshot into the destination — value, styleId, and (only on\n  // a same-sheet move) hyperlinkId / commentId. See copyRange for the\n  // cross-sheet rationale: those indexes are scoped to the source sheet's\n  // own hyperlink / comment arrays and don't translate.\n  for (const entry of snap) {\n    const { row, col, cell } = entry;\n    const dstRow = row + dr;\n    const dstCol = col + dc;\n    const newCell = setCell(dest, dstRow, dstCol, cell.value, cell.styleId);\n    if (sameSheet) {\n      if (cell.hyperlinkId !== undefined) newCell.hyperlinkId = cell.hyperlinkId;\n      if (cell.commentId !== undefined) newCell.commentId = cell.commentId;\n    }\n  }\n  return snap.length;\n}\n\n/**\n * Read all populated values in a single column. Returns one `(CellValue |\n * null)` per row in `[minRow, maxRow]` (defaults to row 1 .. `getMaxRow(ws)`).\n * Empty cells yield `null`. Returns `[]` when the worksheet is empty.\n */\nexport function getColumnValues(\n  ws: Worksheet,\n  col: number,\n  opts: { minRow?: number; maxRow?: number } = {},\n): (CellValue | null)[] {\n  const max = getMaxRow(ws);\n  if (max < 1) return [];\n  const minRow = opts.minRow ?? 1;\n  const maxRow = opts.maxRow ?? max;\n  const out: (CellValue | null)[] = [];\n  for (let r = minRow; r <= maxRow; r++) {\n    const cell = ws.rows.get(r)?.get(col);\n    out.push(cell ? cell.value : null);\n  }\n  return out;\n}\n\n/**\n * Read all populated values in a single row. Returns one `(CellValue | null)`\n * per column in `[minCol, maxCol]` (defaults to col 1 .. `getMaxCol(ws)` when\n * the row exists, otherwise `[]`).\n */\nexport function getRowValues(\n  ws: Worksheet,\n  row: number,\n  opts: { minCol?: number; maxCol?: number } = {},\n): (CellValue | null)[] {\n  const rowMap = ws.rows.get(row);\n  if (!rowMap || rowMap.size === 0) {\n    if (opts.minCol === undefined && opts.maxCol === undefined) return [];\n  }\n  const minCol = opts.minCol ?? 1;\n  // Manual scan avoids `Math.max(...rowMap.keys())`. Spread into a builtin is\n  // limited by the engine's argument-count cap (~125 k on V8), and `getRowValues`\n  // is documented to handle every column up to MAX_COL (16384). For sparse\n  // rows the spread is fine in practice; for dense rows it would silently\n  // throw a stack overflow — surface the cost in a single linear scan instead.\n  let derivedMax = 0;\n  if (rowMap && opts.maxCol === undefined) {\n    for (const c of rowMap.keys()) {\n      if (c > derivedMax) derivedMax = c;\n    }\n  }\n  const maxCol = opts.maxCol ?? derivedMax;\n  if (maxCol < minCol) return [];\n  const out: (CellValue | null)[] = [];\n  for (let c = minCol; c <= maxCol; c++) {\n    const cell = rowMap?.get(c);\n    out.push(cell ? cell.value : null);\n  }\n  return out;\n}\n\n/**\n * Enumerate the populated cells of a row in column order. Unlike {@link\n * getRowValues}, this skips empty columns and yields the cell objects (not just\n * their values). Returns `[]` when the row is absent or empty.\n */\nexport function getCellsInRow(ws: Worksheet, row: number): Cell[] {\n  const rowMap = ws.rows.get(row);\n  if (!rowMap || rowMap.size === 0) return [];\n  const sortedCols = [...rowMap.keys()].sort((a, b) => a - b);\n  const out: Cell[] = [];\n  for (const col of sortedCols) {\n    const cell = rowMap.get(col);\n    if (cell) out.push(cell);\n  }\n  return out;\n}\n\n/**\n * Enumerate the populated cells of a column in row order. Walks the row map and\n * collects whichever rows carry the column. Returns `[]` when the worksheet has\n * no cell in that column.\n */\nexport function getCellsInColumn(ws: Worksheet, col: number): Cell[] {\n  const sortedRows = [...ws.rows.keys()].sort((a, b) => a - b);\n  const out: Cell[] = [];\n  for (const r of sortedRows) {\n    const cell = ws.rows.get(r)?.get(col);\n    if (cell) out.push(cell);\n  }\n  return out;\n}\n\n// ---- column / row dimensions ----------------------------------------------\n\n/**\n * Look up the ColumnDimension covering `col`. The search walks every registered\n * entry's `min..max` range; that's fine for the typical spreadsheet (a handful\n * of column entries) and stays simple.\n */\nexport function getColumnDimension(ws: Worksheet, col: number): ColumnDimension | undefined {\n  for (const dim of ws.columnDimensions.values()) {\n    if (col >= dim.min && col <= dim.max) return dim;\n  }\n  return undefined;\n}\n\n/**\n * Set a single-column ColumnDimension entry covering `col`. Shadows any\n * existing run that overlaps — runs are not split for now (callers that need\n * range-spanning entries can write directly into `ws.columnDimensions`).\n */\nexport function setColumnDimension(\n  ws: Worksheet,\n  col: number,\n  opts: Partial<Omit<ColumnDimension, 'min' | 'max'>>,\n): ColumnDimension {\n  validateRowCol(1, col);\n  // Strip any existing entry that covers this column. Multi-col runs that\n  // straddle `col` are dropped wholesale — phase-5 minimum scope.\n  for (const [key, dim] of ws.columnDimensions) {\n    if (col >= dim.min && col <= dim.max) ws.columnDimensions.delete(key);\n  }\n  const entry = makeColumnDimension(col, opts);\n  ws.columnDimensions.set(col, entry);\n  return entry;\n}\n\n/** Convenience: set a column's width, leaving other fields untouched. */\nexport function setColumnWidth(ws: Worksheet, col: number, width: number): ColumnDimension {\n  const existing = getColumnDimension(ws, col);\n  return setColumnDimension(ws, col, { ...existing, width, customWidth: true });\n}\n\n/** Convenience: hide a column. */\nexport function hideColumn(ws: Worksheet, col: number): ColumnDimension {\n  const existing = getColumnDimension(ws, col);\n  return setColumnDimension(ws, col, { ...existing, hidden: true });\n}\n\n/**\n * Convenience: unhide a column. Drops the `hidden` flag from the column's\n * dimension entry (and removes the entry altogether when no other fields\n * remain).\n */\nexport function unhideColumn(ws: Worksheet, col: number): void {\n  const existing = getColumnDimension(ws, col);\n  if (!existing) return;\n  const { hidden: _drop, ...rest } = existing;\n  const { min: _min, max: _max, ...passthrough } = rest;\n  if (Object.keys(passthrough).length === 0) {\n    ws.columnDimensions.delete(existing.min);\n  } else {\n    setColumnDimension(ws, col, passthrough);\n  }\n}\n\n/** Bulk-hide every column in `[fromCol, toCol]`. */\nexport function hideColumns(ws: Worksheet, fromCol: number, toCol: number): void {\n  if (!Number.isInteger(fromCol) || !Number.isInteger(toCol) || fromCol < 1 || toCol < fromCol) {\n    throw new OpenXmlSchemaError(`hideColumns: invalid column range [${fromCol}, ${toCol}]`);\n  }\n  for (let c = fromCol; c <= toCol; c++) hideColumn(ws, c);\n}\n\n/** Bulk-unhide every column in `[fromCol, toCol]`. */\nexport function unhideColumns(ws: Worksheet, fromCol: number, toCol: number): void {\n  if (!Number.isInteger(fromCol) || !Number.isInteger(toCol) || fromCol < 1 || toCol < fromCol) {\n    throw new OpenXmlSchemaError(`unhideColumns: invalid column range [${fromCol}, ${toCol}]`);\n  }\n  for (let c = fromCol; c <= toCol; c++) unhideColumn(ws, c);\n}\n\n/**\n * Set the default column width (characters) for cells without an explicit\n * ColumnDimension entry. Mirrors Excel's \"Default Width\" dialog. Pass\n * `undefined` to clear.\n */\nexport function setDefaultColumnWidth(ws: Worksheet, width: number | undefined): void {\n  if (width === undefined) {\n    delete (ws as { defaultColumnWidth?: number }).defaultColumnWidth;\n    return;\n  }\n  if (!Number.isFinite(width) || width < 0) {\n    throw new OpenXmlSchemaError(`setDefaultColumnWidth: width must be a non-negative number; got ${width}`);\n  }\n  ws.defaultColumnWidth = width;\n}\n\n/**\n * Set the default row height (points) for rows without an explicit RowDimension\n * entry. Mirrors Excel's \"Default Row Height\" dialog. Pass `undefined` to\n * clear.\n */\nexport function setDefaultRowHeight(ws: Worksheet, height: number | undefined): void {\n  if (height === undefined) {\n    delete (ws as { defaultRowHeight?: number }).defaultRowHeight;\n    return;\n  }\n  if (!Number.isFinite(height) || height < 0) {\n    throw new OpenXmlSchemaError(`setDefaultRowHeight: height must be a non-negative number; got ${height}`);\n  }\n  ws.defaultRowHeight = height;\n}\n\nconst validateOutlineLevel = (level: number): void => {\n  // Excel outline depth is bounded at 7 levels (Data → Group nesting cap).\n  if (!Number.isInteger(level) || level < 1 || level > 7) {\n    throw new OpenXmlSchemaError(`outlineLevel must be an integer in [1, 7]; got ${level}`);\n  }\n};\n\n/**\n * Mirror Excel's \"Data → Group → Rows\" by stamping every row in `[fromRow,\n * toRow]` with an outline depth of `level` (default 1). Allocates a\n * RowDimension for each row that doesn't already have one. Ungroup with {@link\n * ungroupRows}.\n */\nexport function groupRows(ws: Worksheet, fromRow: number, toRow: number, level = 1): void {\n  validateOutlineLevel(level);\n  if (!Number.isInteger(fromRow) || !Number.isInteger(toRow) || fromRow < 1 || toRow < fromRow) {\n    throw new OpenXmlSchemaError(`groupRows: invalid row range [${fromRow}, ${toRow}]`);\n  }\n  for (let r = fromRow; r <= toRow; r++) {\n    const existing = getRowDimension(ws, r) ?? {};\n    setRowDimension(ws, r, { ...existing, outlineLevel: level });\n  }\n}\n\n/**\n * Drop the outline grouping for every row in `[fromRow, toRow]`. Removes the\n * `outlineLevel` field from each affected RowDimension.\n */\nexport function ungroupRows(ws: Worksheet, fromRow: number, toRow: number): void {\n  if (!Number.isInteger(fromRow) || !Number.isInteger(toRow) || fromRow < 1 || toRow < fromRow) {\n    throw new OpenXmlSchemaError(`ungroupRows: invalid row range [${fromRow}, ${toRow}]`);\n  }\n  for (let r = fromRow; r <= toRow; r++) {\n    const existing = ws.rowDimensions.get(r);\n    if (!existing) continue;\n    const { outlineLevel: _drop, ...rest } = existing;\n    if (Object.keys(rest).length === 0) ws.rowDimensions.delete(r);\n    else ws.rowDimensions.set(r, rest);\n  }\n}\n\n/**\n * Mirror Excel's \"Data → Group → Columns\" by stamping every column in\n * `[fromCol, toCol]` with an outline depth of `level` (default 1).\n */\nexport function groupColumns(ws: Worksheet, fromCol: number, toCol: number, level = 1): void {\n  validateOutlineLevel(level);\n  if (!Number.isInteger(fromCol) || !Number.isInteger(toCol) || fromCol < 1 || toCol < fromCol) {\n    throw new OpenXmlSchemaError(`groupColumns: invalid column range [${fromCol}, ${toCol}]`);\n  }\n  for (let c = fromCol; c <= toCol; c++) {\n    const existing = getColumnDimension(ws, c);\n    setColumnDimension(ws, c, { ...existing, outlineLevel: level });\n  }\n}\n\n/**\n * Drop the outline grouping for every column in `[fromCol, toCol]`. Removes the\n * `outlineLevel` field from each affected ColumnDimension.\n */\nexport function ungroupColumns(ws: Worksheet, fromCol: number, toCol: number): void {\n  if (!Number.isInteger(fromCol) || !Number.isInteger(toCol) || fromCol < 1 || toCol < fromCol) {\n    throw new OpenXmlSchemaError(`ungroupColumns: invalid column range [${fromCol}, ${toCol}]`);\n  }\n  for (let c = fromCol; c <= toCol; c++) {\n    const existing = getColumnDimension(ws, c);\n    if (!existing) continue;\n    const { outlineLevel: _drop, ...rest } = existing;\n    // setColumnDimension expects the partial-without-min-max shape.\n    const { min: _min, max: _max, ...passthrough } = rest;\n    if (Object.keys(passthrough).length === 0) {\n      // Pure outline-only entry — drop it entirely.\n      ws.columnDimensions.delete(existing.min);\n    } else {\n      setColumnDimension(ws, c, passthrough);\n    }\n  }\n}\n\n/**\n * Collapse a row outline group: hide every row in `[fromRow, toRow]` and mark\n * them `collapsed: true`. Mirrors Excel's `−` button on a grouped row strip.\n * Rows must already carry an `outlineLevel` from {@link groupRows} for the\n * collapse to render correctly.\n */\nexport function collapseRowGroup(ws: Worksheet, fromRow: number, toRow: number): void {\n  if (!Number.isInteger(fromRow) || !Number.isInteger(toRow) || fromRow < 1 || toRow < fromRow) {\n    throw new OpenXmlSchemaError(`collapseRowGroup: invalid row range [${fromRow}, ${toRow}]`);\n  }\n  for (let r = fromRow; r <= toRow; r++) {\n    const existing = getRowDimension(ws, r) ?? {};\n    setRowDimension(ws, r, { ...existing, hidden: true, collapsed: true });\n  }\n}\n\n/**\n * Expand a row outline group: drop the `hidden` and `collapsed` flags on every\n * row in `[fromRow, toRow]`. Leaves `outlineLevel` and other dimensions intact.\n */\nexport function expandRowGroup(ws: Worksheet, fromRow: number, toRow: number): void {\n  if (!Number.isInteger(fromRow) || !Number.isInteger(toRow) || fromRow < 1 || toRow < fromRow) {\n    throw new OpenXmlSchemaError(`expandRowGroup: invalid row range [${fromRow}, ${toRow}]`);\n  }\n  for (let r = fromRow; r <= toRow; r++) {\n    const existing = ws.rowDimensions.get(r);\n    if (!existing) continue;\n    const { hidden: _h, collapsed: _c, ...rest } = existing;\n    if (Object.keys(rest).length === 0) ws.rowDimensions.delete(r);\n    else ws.rowDimensions.set(r, rest);\n  }\n}\n\n/**\n * Collapse a column outline group: hide + mark `collapsed: true` for every\n * column in `[fromCol, toCol]`. Columns must already carry an `outlineLevel`\n * from {@link groupColumns} for the collapse to render correctly.\n */\nexport function collapseColumnGroup(ws: Worksheet, fromCol: number, toCol: number): void {\n  if (!Number.isInteger(fromCol) || !Number.isInteger(toCol) || fromCol < 1 || toCol < fromCol) {\n    throw new OpenXmlSchemaError(`collapseColumnGroup: invalid column range [${fromCol}, ${toCol}]`);\n  }\n  for (let c = fromCol; c <= toCol; c++) {\n    const existing = getColumnDimension(ws, c);\n    setColumnDimension(ws, c, { ...existing, hidden: true, collapsed: true });\n  }\n}\n\n/**\n * Expand a column outline group: drop `hidden` and `collapsed` from every\n * column in `[fromCol, toCol]`. Leaves `outlineLevel` intact.\n */\nexport function expandColumnGroup(ws: Worksheet, fromCol: number, toCol: number): void {\n  if (!Number.isInteger(fromCol) || !Number.isInteger(toCol) || fromCol < 1 || toCol < fromCol) {\n    throw new OpenXmlSchemaError(`expandColumnGroup: invalid column range [${fromCol}, ${toCol}]`);\n  }\n  for (let c = fromCol; c <= toCol; c++) {\n    const existing = getColumnDimension(ws, c);\n    if (!existing) continue;\n    const { hidden: _h, collapsed: _coll, ...rest } = existing;\n    const { min: _min, max: _max, ...passthrough } = rest;\n    if (Object.keys(passthrough).length === 0) {\n      ws.columnDimensions.delete(existing.min);\n    } else {\n      setColumnDimension(ws, c, passthrough);\n    }\n  }\n}\n\n/**\n * Per-cell effective string length, optionally scaled by the cell's font size\n * relative to Excel's default 11pt baseline.\n */\nconst effectiveLength = (cell: Cell, wb: { styles: { cellXfs: ReadonlyArray<{ fontId: number }>; fonts: ReadonlyArray<{ size?: number }> } } | undefined): number => {\n  const len = cellValueAsString(cell.value).length;\n  if (!wb) return len;\n  const xf = wb.styles.cellXfs[cell.styleId];\n  const fontId = xf?.fontId ?? 0;\n  const font = wb.styles.fonts[fontId];\n  const size = font?.size ?? 11;\n  // Linear scale: 11pt → 1.0; 22pt → 2.0; etc. Excel's actual character width\n  // grows roughly linearly with point size.\n  return len * (size / 11);\n};\n\n/**\n * Approximate autofit for a column. Scans every populated cell in `col` (or in\n * `[opts.minRow, opts.maxRow]`), measures `cellValueAsString` length, and sets\n * the column width to `max(length) + padding`, clamped to `[opts.min ?? 4,\n * opts.max ?? 80]` and bounded above by Excel's hard limit of 255.\n *\n * Note: this is a string-length approximation — Excel sizes columns with the\n * font's actual character-width metrics. For plain ASCII in the default Calibri\n * 11 face the result is usually within ±1 width unit; CJK / wide glyphs need\n * extra padding.\n *\n * Pass `opts.workbook` (or use the `Wb` variant via `autofitColumns`) to enable\n * font-aware scaling — each cell's length is scaled by `(cellFont.size / 11)`\n * so 22pt headings get roughly 2× width.\n */\nexport function autofitColumn(\n  ws: Worksheet,\n  col: number,\n  opts: {\n    minRow?: number;\n    maxRow?: number;\n    padding?: number;\n    min?: number;\n    max?: number;\n    workbook?: { styles: { cellXfs: ReadonlyArray<{ fontId: number }>; fonts: ReadonlyArray<{ size?: number }> } };\n  } = {},\n): ColumnDimension | undefined {\n  const padding = opts.padding ?? 2;\n  const minWidth = opts.min ?? 4;\n  const maxWidth = Math.min(opts.max ?? 80, 255);\n  const minRow = opts.minRow ?? 1;\n  const maxRow = opts.maxRow ?? getMaxRow(ws);\n  if (maxRow < minRow) return undefined;\n  let widest = 0;\n  for (let r = minRow; r <= maxRow; r++) {\n    const cell = ws.rows.get(r)?.get(col);\n    if (!cell) continue;\n    const len = effectiveLength(cell, opts.workbook);\n    if (len > widest) widest = len;\n  }\n  if (widest === 0) return undefined;\n  const width = Math.max(minWidth, Math.min(maxWidth, widest + padding));\n  return setColumnWidth(ws, col, width);\n}\n\n/**\n * Approximate autofit for every column with at least one populated cell. Walks\n * the worksheet once collecting per-column widest-length + applies {@link\n * autofitColumn} per column. `opts.workbook` enables font-size-aware scaling;\n * without it the helper falls back to plain string length.\n */\nexport function autofitColumns(\n  ws: Worksheet,\n  opts: {\n    padding?: number;\n    min?: number;\n    max?: number;\n    workbook?: { styles: { cellXfs: ReadonlyArray<{ fontId: number }>; fonts: ReadonlyArray<{ size?: number }> } };\n  } = {},\n): void {\n  const padding = opts.padding ?? 2;\n  const minWidth = opts.min ?? 4;\n  const maxWidth = Math.min(opts.max ?? 80, 255);\n  const widest = new Map<number, number>();\n  for (const rowMap of ws.rows.values()) {\n    for (const [col, cell] of rowMap) {\n      const len = effectiveLength(cell, opts.workbook);\n      const cur = widest.get(col) ?? 0;\n      if (len > cur) widest.set(col, len);\n    }\n  }\n  for (const [col, w] of widest) {\n    if (w === 0) continue;\n    setColumnWidth(ws, col, Math.max(minWidth, Math.min(maxWidth, w + padding)));\n  }\n}\n\n/**\n * Set widths for many columns in one call. `widths` maps either:\n * - an array `[12, 16, 20]` interpreted positionally starting at\n * column `startCol` (default 1), or\n * - a `Record<number, number>` keyed by 1-based column index.\n * Each entry sets `customWidth: true`.\n */\nexport function setColumnWidths(\n  ws: Worksheet,\n  widths: ReadonlyArray<number> | Record<number, number>,\n  startCol = 1,\n): void {\n  if (Array.isArray(widths)) {\n    for (let i = 0; i < widths.length; i++) {\n      const w = widths[i];\n      if (typeof w !== 'number' || !Number.isFinite(w)) continue;\n      setColumnWidth(ws, startCol + i, w);\n    }\n  } else {\n    for (const [k, w] of Object.entries(widths as Record<number, number>)) {\n      const col = Number.parseInt(k, 10);\n      if (!Number.isInteger(col) || col < 1) continue;\n      if (typeof w !== 'number' || !Number.isFinite(w)) continue;\n      setColumnWidth(ws, col, w);\n    }\n  }\n}\n\n/** Look up a row's dimension entry. */\nexport function getRowDimension(ws: Worksheet, row: number): RowDimension | undefined {\n  return ws.rowDimensions.get(row);\n}\n\nexport function setRowDimension(ws: Worksheet, row: number, opts: Partial<RowDimension>): RowDimension {\n  validateRowCol(row, 1);\n  const entry = makeRowDimension(opts);\n  ws.rowDimensions.set(row, entry);\n  return entry;\n}\n\n/** Convenience: set a row's height, marking customHeight=true. */\nexport function setRowHeight(ws: Worksheet, row: number, height: number): RowDimension {\n  const existing = getRowDimension(ws, row);\n  return setRowDimension(ws, row, { ...existing, height, customHeight: true });\n}\n\n/**\n * Set heights for many rows in one call. `heights` accepts an array (positional\n * from `startRow`, default 1) or a `Record<number, number>` keyed by 1-based\n * row index. Each entry sets `customHeight: true`.\n */\nexport function setRowHeights(\n  ws: Worksheet,\n  heights: ReadonlyArray<number> | Record<number, number>,\n  startRow = 1,\n): void {\n  if (Array.isArray(heights)) {\n    for (let i = 0; i < heights.length; i++) {\n      const h = heights[i];\n      if (typeof h !== 'number' || !Number.isFinite(h)) continue;\n      setRowHeight(ws, startRow + i, h);\n    }\n  } else {\n    for (const [k, h] of Object.entries(heights as Record<number, number>)) {\n      const row = Number.parseInt(k, 10);\n      if (!Number.isInteger(row) || row < 1) continue;\n      if (typeof h !== 'number' || !Number.isFinite(h)) continue;\n      setRowHeight(ws, row, h);\n    }\n  }\n}\n\n/** Convenience: hide a row. */\nexport function hideRow(ws: Worksheet, row: number): RowDimension {\n  const existing = getRowDimension(ws, row);\n  return setRowDimension(ws, row, { ...existing, hidden: true });\n}\n\n/**\n * Convenience: unhide a row. Drops the `hidden` flag from the row's dimension\n * entry (and removes the entry altogether when no other fields remain).\n */\nexport function unhideRow(ws: Worksheet, row: number): void {\n  const existing = ws.rowDimensions.get(row);\n  if (!existing) return;\n  const { hidden: _drop, ...rest } = existing;\n  if (Object.keys(rest).length === 0) ws.rowDimensions.delete(row);\n  else ws.rowDimensions.set(row, rest);\n}\n\n/** Bulk-hide every row in `[fromRow, toRow]`. */\nexport function hideRows(ws: Worksheet, fromRow: number, toRow: number): void {\n  if (!Number.isInteger(fromRow) || !Number.isInteger(toRow) || fromRow < 1 || toRow < fromRow) {\n    throw new OpenXmlSchemaError(`hideRows: invalid row range [${fromRow}, ${toRow}]`);\n  }\n  for (let r = fromRow; r <= toRow; r++) hideRow(ws, r);\n}\n\n/** Bulk-unhide every row in `[fromRow, toRow]`. */\nexport function unhideRows(ws: Worksheet, fromRow: number, toRow: number): void {\n  if (!Number.isInteger(fromRow) || !Number.isInteger(toRow) || fromRow < 1 || toRow < fromRow) {\n    throw new OpenXmlSchemaError(`unhideRows: invalid row range [${fromRow}, ${toRow}]`);\n  }\n  for (let r = fromRow; r <= toRow; r++) unhideRow(ws, r);\n}\n\n// ---- hyperlinks -----------------------------------------------------------\n\n/**\n * Replace any prior hyperlink on the same `ref` with the given options. Pass `{\n * target }` for an external URL, `{ location }` for an internal jump, or both.\n * Returns the resulting Hyperlink record.\n */\nexport function setHyperlink(\n  ws: Worksheet,\n  ref: string,\n  opts: { target?: string; location?: string; display?: string; tooltip?: string },\n): Hyperlink {\n  if (opts.target === undefined && opts.location === undefined) {\n    throw new OpenXmlSchemaError('setHyperlink: one of target / location is required');\n  }\n  removeHyperlink(ws, ref);\n  const hl = makeHyperlink({ ref, ...opts });\n  ws.hyperlinks.push(hl);\n  return hl;\n}\n\n/** Remove the hyperlink registered against `ref`. Returns true if anything was removed. */\nexport function removeHyperlink(ws: Worksheet, ref: string): boolean {\n  const i = ws.hyperlinks.findIndex((h) => h.ref === ref);\n  if (i < 0) return false;\n  ws.hyperlinks.splice(i, 1);\n  return true;\n}\n\n/** Drop every hyperlink on the worksheet. Returns the count removed. */\nexport function removeAllHyperlinks(ws: Worksheet): number {\n  const n = ws.hyperlinks.length;\n  ws.hyperlinks = [];\n  return n;\n}\n\n/** Look up a hyperlink by its ref. */\nexport function getHyperlink(ws: Worksheet, ref: string): Hyperlink | undefined {\n  return ws.hyperlinks.find((h) => h.ref === ref);\n}\n\n/** Read-only snapshot of every hyperlink on the sheet. */\nexport function listHyperlinks(ws: Worksheet): ReadonlyArray<Hyperlink> {\n  return ws.hyperlinks;\n}\n\n/**\n * Resolve a cell to its hyperlink (if any). Walks every hyperlink entry on the\n * worksheet and returns the first whose `ref` (a single cell `\"A1\"` or a range\n * `\"A1:B5\"`) covers the cell's coordinate. Returns `undefined` when no entry\n * matches.\n */\nexport function getCellHyperlink(ws: Worksheet, c: Cell): Hyperlink | undefined {\n  for (const h of ws.hyperlinks) {\n    const range = parseRange(h.ref);\n    if (rangeContainsCell(range, c.row, c.col)) return h;\n  }\n  return undefined;\n}\n\n/**\n * Resolve a cell to its legacy comment (if any). Same matching rule as {@link\n * getCellHyperlink} — the comment's `ref` may be a single cell or a range, and\n * the first containing entry wins.\n */\nexport function getCellComment(ws: Worksheet, c: Cell): LegacyComment | undefined {\n  for (const cm of ws.legacyComments) {\n    const range = parseRange(cm.ref);\n    if (rangeContainsCell(range, c.row, c.col)) return cm;\n  }\n  return undefined;\n}\n\n// ---- data validations ----------------------------------------------------\n\n/** Append a DataValidation entry. */\nexport function addDataValidation(ws: Worksheet, dv: DataValidation): DataValidation {\n  ws.dataValidations.push(dv);\n  return dv;\n}\n\n/** Drop every validation whose sqref overlaps `ref` (string parse). Returns count removed. */\nexport function removeDataValidations(ws: Worksheet, predicate: (dv: DataValidation) => boolean): number {\n  const before = ws.dataValidations.length;\n  ws.dataValidations = ws.dataValidations.filter((dv) => !predicate(dv));\n  return before - ws.dataValidations.length;\n}\n\n/** Read-only snapshot of every data validation block on the sheet. */\nexport function listDataValidations(ws: Worksheet): ReadonlyArray<DataValidation> {\n  return ws.dataValidations;\n}\n\n/** Drop every data validation block on the worksheet. Returns the count removed. */\nexport function removeAllDataValidations(ws: Worksheet): number {\n  const n = ws.dataValidations.length;\n  ws.dataValidations = [];\n  return n;\n}\n\n// ---- autoFilter ----------------------------------------------------------\n\n/** Set or replace the worksheet's AutoFilter. Pass `undefined` to clear. */\nexport function setAutoFilter(ws: Worksheet, filter: AutoFilter | undefined): void {\n  if (filter === undefined) {\n    delete ws.autoFilter;\n    return;\n  }\n  ws.autoFilter = filter;\n}\n\n/** Read the current AutoFilter, if any. */\nexport function getAutoFilter(ws: Worksheet): AutoFilter | undefined {\n  return ws.autoFilter;\n}\n\n// ---- tables --------------------------------------------------------------\n\n/** Append a table. The id and displayName must be workbook-unique — the caller is responsible. */\nexport function addTable(ws: Worksheet, table: TableDefinition): TableDefinition {\n  ws.tables.push(table);\n  return table;\n}\n\n/** Look up a table by displayName. */\nexport function getTable(ws: Worksheet, displayName: string): TableDefinition | undefined {\n  return ws.tables.find((t) => t.displayName === displayName);\n}\n\n/** Read-only snapshot of every Excel table defined on the sheet. */\nexport function listTables(ws: Worksheet): ReadonlyArray<TableDefinition> {\n  return ws.tables;\n}\n\n/** Drop a table by displayName. Returns true when something was removed. */\nexport function removeTable(ws: Worksheet, displayName: string): boolean {\n  const i = ws.tables.findIndex((t) => t.displayName === displayName);\n  if (i < 0) return false;\n  ws.tables.splice(i, 1);\n  return true;\n}\n\n/** Drop every Excel table on the worksheet. Returns the count removed. */\nexport function removeAllTables(ws: Worksheet): number {\n  const n = ws.tables.length;\n  ws.tables = [];\n  return n;\n}\n\n// ---- legacy comments -----------------------------------------------------\n\n/** Add or replace the comment at `ref`. */\nexport function setComment(ws: Worksheet, opts: { ref: string; author: string; text: string }): LegacyComment {\n  const i = ws.legacyComments.findIndex((c) => c.ref === opts.ref);\n  const c = makeLegacyComment(opts);\n  if (i < 0) ws.legacyComments.push(c);\n  else ws.legacyComments[i] = c;\n  return c;\n}\n\nexport function getComment(ws: Worksheet, ref: string): LegacyComment | undefined {\n  return ws.legacyComments.find((c) => c.ref === ref);\n}\n\nexport function removeComment(ws: Worksheet, ref: string): boolean {\n  const i = ws.legacyComments.findIndex((c) => c.ref === ref);\n  if (i < 0) return false;\n  ws.legacyComments.splice(i, 1);\n  return true;\n}\n\n/** Read-only snapshot of every legacy comment on the sheet. */\nexport function listComments(ws: Worksheet): ReadonlyArray<LegacyComment> {\n  return ws.legacyComments;\n}\n\n/** Drop every legacy comment on the worksheet. Returns the count removed. */\nexport function removeAllComments(ws: Worksheet): number {\n  const n = ws.legacyComments.length;\n  ws.legacyComments = [];\n  return n;\n}\n\n/**\n * Replace just the text of an existing comment, leaving its ref and author\n * untouched. Returns `true` when the comment was found.\n */\nexport function editCommentText(ws: Worksheet, ref: string, newText: string): boolean {\n  const i = ws.legacyComments.findIndex((c) => c.ref === ref);\n  if (i < 0) return false;\n  const c = ws.legacyComments[i];\n  if (!c) return false;\n  ws.legacyComments[i] = makeLegacyComment({ ref: c.ref, author: c.author, text: newText });\n  return true;\n}\n\n/**\n * Replace just the author of an existing comment, leaving its ref and text\n * untouched. Returns `true` when the comment was found.\n */\nexport function editCommentAuthor(ws: Worksheet, ref: string, newAuthor: string): boolean {\n  const i = ws.legacyComments.findIndex((c) => c.ref === ref);\n  if (i < 0) return false;\n  const c = ws.legacyComments[i];\n  if (!c) return false;\n  ws.legacyComments[i] = makeLegacyComment({ ref: c.ref, author: newAuthor, text: c.text });\n  return true;\n}\n\n/**\n * Rename every comment authored by `oldName` to `newName`. Returns the number\n * of comments updated. Useful when consolidating comments after a team handoff\n * (Excel's commentsN.xml dedups authors at save time, so a single rename\n * collapses cleanly).\n */\nexport function renameCommentAuthor(ws: Worksheet, oldName: string, newName: string): number {\n  let n = 0;\n  for (let i = 0; i < ws.legacyComments.length; i++) {\n    const c = ws.legacyComments[i];\n    if (c && c.author === oldName) {\n      ws.legacyComments[i] = makeLegacyComment({ ref: c.ref, author: newName, text: c.text });\n      n++;\n    }\n  }\n  return n;\n}\n\n/** Filter every legacy comment by author. */\nexport function findCommentsByAuthor(ws: Worksheet, author: string): ReadonlyArray<LegacyComment> {\n  return ws.legacyComments.filter((c) => c.author === author);\n}\n\n// ---- conditional formatting ----------------------------------------------\n\n/** Append a conditional formatting block. */\nexport function addConditionalFormatting(ws: Worksheet, cf: ConditionalFormatting): ConditionalFormatting {\n  ws.conditionalFormatting.push(cf);\n  return cf;\n}\n\n/** All conditional formatting blocks (read-only view). */\nexport function getConditionalFormatting(ws: Worksheet): ReadonlyArray<ConditionalFormatting> {\n  return ws.conditionalFormatting;\n}\n\n/** Drop every conditional-formatting block on the worksheet. Returns the count removed. */\nexport function removeAllConditionalFormatting(ws: Worksheet): number {\n  const n = ws.conditionalFormatting.length;\n  ws.conditionalFormatting = [];\n  return n;\n}\n\n// ---- cell watches / ignored errors --------------------------------------\n\n/** Pin a cell to the Watch Window. Returns the pushed entry. */\nexport function addCellWatch(ws: Worksheet, watch: CellWatch): CellWatch {\n  ws.cellWatches.push(watch);\n  return watch;\n}\n\n/** Remove cell watches matching `predicate`. Returns the count removed. */\nexport function removeCellWatches(ws: Worksheet, predicate: (w: CellWatch) => boolean): number {\n  const before = ws.cellWatches.length;\n  ws.cellWatches = ws.cellWatches.filter((w) => !predicate(w));\n  return before - ws.cellWatches.length;\n}\n\n/** Append an ignored-error region. */\nexport function addIgnoredError(ws: Worksheet, ie: IgnoredError): IgnoredError {\n  ws.ignoredErrors.push(ie);\n  return ie;\n}\n\n/** Remove ignored-error entries matching `predicate`. Returns the count removed. */\nexport function removeIgnoredErrors(ws: Worksheet, predicate: (ie: IgnoredError) => boolean): number {\n  const before = ws.ignoredErrors.length;\n  ws.ignoredErrors = ws.ignoredErrors.filter((ie) => !predicate(ie));\n  return before - ws.ignoredErrors.length;\n}\n"],"mappings":";;;;;AAuBA,SAAgB,cAAc,QAAgB,QAAgB,QAAgB,QAA2B;CACvG,IACE,CAAC,OAAO,UAAU,MAAM,KACxB,CAAC,OAAO,UAAU,MAAM,KACxB,CAAC,OAAO,UAAU,MAAM,KACxB,CAAC,OAAO,UAAU,MAAM,GAExB,MAAM,IAAI,mBAAmB,mCAAmC;CAElE,IAAI,SAAS,KAAK,SAAS,KAAK,SAAA,WAAoB,SAAA,SAClD,MAAM,IAAI,mBAAmB,uCAAuC,QAAQ,EAAE;CAEhF,IAAI,SAAS,KAAK,SAAS,KAAK,SAAA,SAAoB,SAAA,OAClD,MAAM,IAAI,mBAAmB,uCAAuC,QAAQ,EAAE;CAEhF,OAAO;EACL,QAAQ,KAAK,IAAI,QAAQ,MAAM;EAC/B,QAAQ,KAAK,IAAI,QAAQ,MAAM;EAC/B,QAAQ,KAAK,IAAI,QAAQ,MAAM;EAC/B,QAAQ,KAAK,IAAI,QAAQ,MAAM;CACjC;AACF;;AAGA,SAAgB,WAAW,OAA0B;CACnD,OAAO,gBAAgB,KAAK;AAC9B;;AAGA,SAAgB,cAAc,GAAsB;CAClD,OAAO,wBAAwB,CAAC;AAClC;;AA+BA,SAAgB,kBAAkB,GAAc,KAAa,KAAsB;CACjF,OAAO,OAAO,EAAE,UAAU,OAAO,EAAE,UAAU,OAAO,EAAE,UAAU,OAAO,EAAE;AAC3E;;;;;;AAOA,SAAgB,cAAc,SAAiB,UAA2B;CACxE,MAAM,EAAE,KAAK,QAAQ,kBAAkB,OAAO;CAC9C,OAAO,kBAAkB,WAAW,QAAQ,GAAG,KAAK,GAAG;AACzD;;;;;;;AAQA,SAAgB,eAAe,OAAe,OAAwB;CACpE,OAAO,mBAAmB,WAAW,KAAK,GAAG,WAAW,KAAK,CAAC;AAChE;;;;;;;;;;AAoEA,SAAgB,eAAe,OAAe,WAAmB,WAA2B;CAC1F,IAAI,CAAC,OAAO,UAAU,SAAS,KAAK,CAAC,OAAO,UAAU,SAAS,GAC7D,MAAM,IAAI,mBAAmB,yCAAyC;CAExE,MAAM,IAAI,WAAW,KAAK;CAC1B,OAAO,cAAc,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,WAAW,EAAE,SAAS,SAAS,CAAC;AACpG;;AAGA,SAAgB,mBAAmB,OAAkB,OAA2B;CAC9E,OACE,MAAM,UAAU,MAAM,UACtB,MAAM,UAAU,MAAM,UACtB,MAAM,UAAU,MAAM,UACtB,MAAM,UAAU,MAAM;AAE1B;;;;;;AAOA,SAAgB,WAAW,GAAc,IAAY,IAAuB;CAC1E,IAAI,CAAC,OAAO,UAAU,EAAE,KAAK,CAAC,OAAO,UAAU,EAAE,GAC/C,MAAM,IAAI,mBAAmB,sCAAsC;CAErE,OAAO,cAAc,EAAE,SAAS,IAAI,EAAE,SAAS,IAAI,EAAE,SAAS,IAAI,EAAE,SAAS,EAAE;AACjF;;AAGA,SAAgB,WAAW,GAAc,GAAyB;CAChE,OAAO;EACL,QAAQ,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;EACnC,QAAQ,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;EACnC,QAAQ,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;EACnC,QAAQ,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CACrC;AACF;;AAGA,SAAgB,kBAAkB,GAAc,GAAgC;CAC9E,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CAC1C,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CAC1C,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CAC1C,MAAM,SAAS,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CAC1C,IAAI,SAAS,UAAU,SAAS,QAAQ,OAAO;CAC/C,OAAO;EAAE;EAAQ;EAAQ;EAAQ;CAAO;AAC1C;;AAGA,SAAgB,cAAc,GAAc,GAAuB;CACjE,OAAO,kBAAkB,GAAG,CAAC,MAAM;AACrC;;AAGA,SAAgB,UAAU,GAAsB;CAC9C,QAAQ,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,SAAS,EAAE,SAAS;AAC5D;;AA0BA,SAAgB,oBAAoB,OAA+B;CACjE,MAAM,SAAsB,CAAC;CAC7B,KAAK,MAAM,SAAS,MAAM,MAAM,KAAK,GAAG;EACtC,IAAI,MAAM,WAAW,GAAG;EACxB,OAAO,KAAK,WAAW,KAAK,CAAC;CAC/B;CACA,OAAO,EAAE,OAAO;AAClB;;AAGA,SAAgB,uBAAuB,GAA2B;CAChE,OAAO,EAAE,OAAO,IAAI,aAAa,CAAC,CAAC,KAAK,GAAG;AAC7C;;AAUA,SAAgB,2BAA2B,GAAmB,KAAa,KAAsB;CAC/F,KAAK,MAAM,KAAK,EAAE,QAAQ,IAAI,kBAAkB,GAAG,KAAK,GAAG,GAAG,OAAO;CACrE,OAAO;AACT;;;;;;;ACtPA,MAAa,cAAiC,OAAO,OAAO;CAC1D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAWD,MAAM,UAAU;;;;;;AAOhB,SAAgB,aAAa,OAAuB;CAClD,IAAI,OAAO,UAAU,YAAY,CAAC,QAAQ,KAAK,KAAK,GAClD,MAAM,IAAI,mBAAmB,6CAA6C,MAAM,EAAE;CAEpF,QAAQ,MAAM,WAAW,IAAI,KAAK,UAAU,MAAA,CAAO,YAAY;AACjE;;;;;AAMA,SAAgB,UAAU,OAAuB,CAAC,GAAU;CAC1D,MAAM,MAAsB,CAAC;CAC7B,IAAI,KAAK,QAAQ,KAAA,GAAW,IAAI,MAAM,aAAa,KAAK,GAAG;CAC3D,IAAI,KAAK,YAAY,KAAA,GAAW;EAC9B,IAAI,CAAC,OAAO,UAAU,KAAK,OAAO,KAAK,KAAK,UAAU,KAAK,KAAK,UAAU,IACxE,MAAM,IAAI,mBAAmB,yCAAyC,KAAK,SAAS;EAEtF,IAAI,UAAU,KAAK;CACrB;CACA,IAAI,KAAK,UAAU,KAAA,GAAW;EAC5B,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,KAAK,KAAK,QAAQ,GAChD,MAAM,IAAI,mBAAmB,mDAAmD,KAAK,OAAO;EAE9F,IAAI,QAAQ,KAAK;CACnB;CACA,IAAI,KAAK,SAAS,KAAA,GAAW,IAAI,OAAO,KAAK;CAC7C,IAAI,KAAK,SAAS,KAAA,GAAW;EAC3B,IAAI,CAAC,OAAO,SAAS,KAAK,IAAI,KAAK,KAAK,OAAO,MAAM,KAAK,OAAO,GAC/D,MAAM,IAAI,mBAAmB,sCAAsC,KAAK,MAAM;EAEhF,IAAI,OAAO,KAAK;CAClB;CACA,OAAO,OAAO,OAAO,GAAG;AAC1B;;;;;AAMA,SAAgB,oBAAoB,KAAiC;CACnE,OAAO,YAAY;AACrB;;AAGA,SAAgB,SAAS,KAAoB;CAC3C,OAAO,UAAU,EAAE,KAAK,IAAI,CAAC;AAC/B;;;;;;;AAQA,SAAgB,WAAW,OAA8C;CACvE,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,IAAI,MAAM,QAAQ,KAAA,GAAW,OAAO,aAAa,MAAM,GAAG;CAC1D,IAAI,MAAM,YAAY,KAAA,GAAW;EAC/B,MAAM,MAAM,oBAAoB,MAAM,OAAO;EAC7C,IAAI,KAAK,OAAO,IAAI,YAAY;CAClC;AAEF;;;;;;AAOA,SAAgB,UAAU,KAAqB;CAC7C,MAAM,MAAM,aAAa,GAAG;CAC5B,MAAM,IAAI,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;CACjD,MAAM,IAAI,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;CACjD,MAAM,IAAI,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;CACjD,MAAM,OAAO,MAAuB,KAAK,SAAU,IAAI,UAAU,IAAI,QAAS,UAAU;CACxF,OAAO,QAAS,IAAI,CAAC,IAAI,QAAS,IAAI,CAAC,IAAI,QAAS,IAAI,CAAC;AAC3D;;;;;;AAOA,SAAgB,cAAc,MAAc,MAAsB;CAChE,MAAM,KAAK,UAAU,IAAI;CACzB,MAAM,KAAK,UAAU,IAAI;CACzB,MAAM,CAAC,IAAI,MAAM,MAAM,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;CAC9C,QAAQ,KAAK,QAAS,KAAK;AAC7B;;;;;;AAOA,SAAgB,sBAAsB,eAAgD;CAGpF,OAAO,UAAU,aAAa,IAAI,OAAQ,aAAa;AACzD;AAEA,MAAM,aAAa,QAAgE;CACjF,MAAM,MAAM,aAAa,GAAG;CAC5B,OAAO;EACL,GAAG,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EACtC,GAAG,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EACtC,GAAG,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EACtC,GAAG,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;CACxC;AACF;AAEA,MAAM,aAAa,MAAsB;CAEvC,OADU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,CAAC,CAAC,CAC1C,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,YAAY;AACrD;AAEA,MAAM,aAAa,MAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;;;;;;AAOnE,SAAgB,QAAQ,KAAa,QAAwB;CAC3D,MAAM,IAAI,UAAU,MAAM;CAC1B,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM,UAAU,GAAG;CACpC,OAAO,GAAG,UAAU,CAAC,IAAI,UAAU,KAAK,MAAM,KAAK,CAAC,IAAI,UAAU,KAAK,MAAM,KAAK,CAAC,IAAI,UAAU,KAAK,MAAM,KAAK,CAAC;AACpH;;;;;AAMA,SAAgB,OAAO,KAAa,QAAwB;CAC1D,MAAM,IAAI,UAAU,MAAM;CAC1B,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM,UAAU,GAAG;CACpC,OAAO,GAAG,UAAU,CAAC,IAAI,UAAU,KAAK,IAAI,EAAE,IAAI,UAAU,KAAK,IAAI,EAAE,IAAI,UAAU,KAAK,IAAI,EAAE;AAClG;;;;;AAMA,SAAgB,UAAU,MAAc,MAAc,GAAmB;CACvE,MAAM,IAAI,UAAU,CAAC;CACrB,MAAM,IAAI,UAAU,IAAI;CACxB,MAAM,IAAI,UAAU,IAAI;CACxB,OAAO,GAAG,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC;AACpJ;;;;;;;AAQA,SAAgB,SAAS,KAA6D;CACpF,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,UAAU,GAAG;CAChD,MAAM,IAAI,KAAK;CACf,MAAM,IAAI,KAAK;CACf,MAAM,IAAI,KAAK;CACf,MAAM,MAAM,KAAK,IAAI,GAAG,GAAG,CAAC;CAC5B,MAAM,MAAM,KAAK,IAAI,GAAG,GAAG,CAAC;CAC5B,MAAM,KAAK,MAAM,OAAO;CACxB,IAAI,IAAI;CACR,IAAI,IAAI;CACR,IAAI,QAAQ,KAAK;EACf,MAAM,IAAI,MAAM;EAChB,IAAI,IAAI,KAAM,KAAK,IAAI,MAAM,OAAO,KAAK,MAAM;EAC/C,IAAI,QAAQ,GAAG,MAAM,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,MAAM;OAChD,IAAI,QAAQ,GAAG,MAAM,IAAI,KAAK,IAAI,KAAK;OACvC,MAAM,IAAI,KAAK,IAAI,KAAK;CAC/B;CACA,OAAO;EAAE;EAAG;EAAG;EAAG;CAAE;AACtB;;;;;;AAOA,SAAgB,UAAU,KAAa,SAAyB;CAC9D,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM,SAAS,GAAG;CACnC,OAAO,SAAS,IAAI,SAAS,GAAG,GAAG,CAAC;AACtC;;;;;;AAOA,SAAgB,iBAAiB,KAAa,OAAuB;CACnE,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM,SAAS,GAAG;CACnC,OAAO,SAAS,GAAG,IAAI,OAAO,GAAG,CAAC;AACpC;;;;;;;AAQA,SAAgB,gBAAgB,KAAa,OAAuB;CAClE,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM,SAAS,GAAG;CACnC,OAAO,SAAS,GAAG,GAAG,IAAI,OAAO,CAAC;AACpC;;;;;;AAOA,SAAgB,SAAS,GAAW,GAAW,GAAW,QAAQ,KAAa;CAC7E,MAAM,MAAO,IAAI,MAAO,OAAO;CAC/B,MAAM,KAAK,UAAU,CAAC;CACtB,MAAM,KAAK,UAAU,CAAC;CACtB,MAAM,KAAK,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK;CACvC,MAAM,IAAI,KAAK,IAAI,KAAK,IAAM,KAAK,KAAM,IAAK,CAAC;CAC/C,MAAM,IAAI,KAAK,IAAI;CACnB,IAAI,KAAK;CACT,IAAI,KAAK;CACT,IAAI,KAAK;CACT,IAAI,KAAK,IAAI;EACX,KAAK;EACL,KAAK;CACP,OAAO,IAAI,KAAK,KAAK;EACnB,KAAK;EACL,KAAK;CACP,OAAO,IAAI,KAAK,KAAK;EACnB,KAAK;EACL,KAAK;CACP,OAAO,IAAI,KAAK,KAAK;EACnB,KAAK;EACL,KAAK;CACP,OAAO,IAAI,KAAK,KAAK;EACnB,KAAK;EACL,KAAK;CACP,OAAO;EACL,KAAK;EACL,KAAK;CACP;CAEA,OAAO,GAAG,UADA,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,CAAC,CACjC,CAAC,IAAI,WAAW,KAAK,KAAK,GAAG,IAAI,WAAW,KAAK,KAAK,GAAG,IAAI,WAAW,KAAK,KAAK,GAAG;AAC3G;;;;AC5TA,SAAgB,oBACd,KACA,OAAsD,CAAC,GACtC;CACjB,OAAO;EACL,KAAK;EACL,KAAK;EACL,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;EACxD,GAAI,KAAK,gBAAgB,KAAA,IAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAC1E,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,YAAY,KAAA,IAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;EAC9D,GAAI,KAAK,iBAAiB,KAAA,IAAY,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;EAC7E,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;EACxD,GAAI,KAAK,cAAc,KAAA,IAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;CACtE;AACF;AAEA,SAAgB,iBAAiB,OAA8B,CAAC,GAAiB;CAC/E,OAAO;EACL,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,iBAAiB,KAAA,IAAY,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;EAC7E,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,iBAAiB,KAAA,IAAY,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;EAC7E,GAAI,KAAK,cAAc,KAAA,IAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;EACpE,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;CAC1D;AACF;;;ACnDA,SAAgB,cAAc,MAAuD;CACnF,IAAI,KAAK,QAAQ,KAAA,KAAa,KAAK,IAAI,WAAW,GAChD,MAAM,IAAI,mBAAmB,4BAA4B;CAE3D,OAAO;EACL,KAAK,KAAK;EACV,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,aAAa,KAAA,IAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;EACjE,GAAI,KAAK,YAAY,KAAA,IAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;EAC9D,GAAI,KAAK,YAAY,KAAA,IAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;EAC9D,GAAI,KAAK,QAAQ,KAAA,IAAY,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;CACpD;AACF;;;;ACgBA,SAAgB,cAAc,OAA2B,CAAC,GAAc;CACtE,OAAO;EACL,gBAAgB,KAAK,kBAAkB;EACvC,GAAI,KAAK,gBAAgB,KAAA,IAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAC1E,GAAI,KAAK,kBAAkB,KAAA,IAAY,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;EAChF,GAAI,KAAK,sBAAsB,KAAA,IAAY,EAAE,mBAAmB,KAAK,kBAAkB,IAAI,CAAC;EAC5F,GAAI,KAAK,iBAAiB,KAAA,IAAY,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;EAC7E,GAAI,KAAK,cAAc,KAAA,IAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;EACpE,GAAI,KAAK,gBAAgB,KAAA,IAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAC1E,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACrD,GAAI,KAAK,gBAAgB,KAAA,IAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAC1E,GAAI,KAAK,cAAc,KAAA,IAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;EACpE,GAAI,KAAK,oBAAoB,KAAA,IAAY,EAAE,iBAAiB,KAAK,gBAAgB,IAAI,CAAC;EACtF,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACvC,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;CACxD;AACF;;;;;;;;AASA,SAAgB,eAAe,YAA0B;CACvD,MAAM,EAAE,KAAK,QAAQ,kBAAkB,UAAU;CACjD,IAAI,QAAQ,KAAK,QAAQ,GACvB,MAAM,IAAI,mBAAmB,iFAA+E;CAE9G,MAAM,SAAS,MAAM;CACrB,MAAM,SAAS,MAAM;CACrB,IAAI;CACJ,IAAI,SAAS,KAAK,SAAS,GAAG,aAAa;MACtC,IAAI,SAAS,GAAG,aAAa;MAC7B,aAAa;CAClB,MAAM,OAAa;EACjB,OAAO;EACP,aAAa;EACb;CACF;CACA,IAAI,SAAS,GAAG,KAAK,SAAS;CAC9B,IAAI,SAAS,GAAG,KAAK,SAAS;CAC9B,OAAO;AACT;;AAGA,SAAgB,cAAc,MAAqC;CACjE,MAAM,OAAO,KAAK;CAClB,IAAI,CAAC,QAAQ,KAAK,UAAU,UAAU,OAAO,KAAA;CAC7C,IAAI,KAAK,aAAa,OAAO,KAAK;CAClC,MAAM,SAAS,KAAK,UAAU;CAC9B,MAAM,SAAS,KAAK,UAAU;CAC9B,OAAO,kBAAkB,SAAS,GAAG,SAAS,CAAC;AACjD;;;ACzFA,SAAgB,kBAAkB,MAAoE;CACpG,OAAO;EAAE,KAAK,KAAK;EAAK,QAAQ,KAAK;EAAQ,MAAM,KAAK;CAAK;AAC/D;;;AC2BA,MAAa,uBAAuB,OAAwB,CAAC,MAAuB;CAClF,MAAM,MAAuB,CAAC;CAC9B,IAAI,KAAK,aAAa,KAAA,GAAW,IAAI,WAAW,KAAK;CACrD,IAAI,KAAK,sCAAsC,KAAA,GAC7C,IAAI,oCAAoC,KAAK;CAC/C,IAAI,KAAK,eAAe,KAAA,GAAW,IAAI,aAAa,KAAK;CACzD,IAAI,KAAK,cAAc,KAAA,GAAW,IAAI,YAAY,KAAK;CACvD,IAAI,KAAK,mBAAmB,KAAA,GAAW,IAAI,iBAAiB,KAAK;CACjE,IAAI,KAAK,YAAY,KAAA,GAAW,IAAI,UAAU,KAAK;CACnD,IAAI,KAAK,iBAAiB,KAAA,GAAW,IAAI,eAAe,KAAK;CAC7D,IAAI,KAAK,yBAAyB,KAAA,GAAW,IAAI,uBAAuB,KAAK;CAC7E,IAAI,KAAK,oBAAoB,KAAA,GAAW,IAAI,kBAAkB,KAAK;CACnE,IAAI,KAAK,aAAa,KAAA,GAAW,IAAI,WAAW,KAAK;CACrD,IAAI,KAAK,cAAc,KAAA,GAAW,IAAI,YAAY,KAAK;CACvD,IAAI,KAAK,gBAAgB,KAAA,GAAW,IAAI,cAAc,KAAK;CAC3D,OAAO;AACT;;;;ACgLA,SAAgB,cAAc,OAA0B;CACtD,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,GAChD,MAAM,IAAI,mBAAmB,4CAA4C;CAE3E,OAAO;EACL;EACA,sBAAM,IAAI,IAAI;EACd,kBAAkB;EAClB,aAAa,CAAC;EACd,OAAO,CAAC;EACR,kCAAkB,IAAI,IAAI;EAC1B,+BAAe,IAAI,IAAI;EACvB,YAAY,CAAC;EACb,iBAAiB,CAAC;EAClB,QAAQ,CAAC;EACT,gBAAgB,CAAC;EACjB,uBAAuB,CAAC;EACxB,aAAa,CAAC;EACd,eAAe,CAAC;EAChB,WAAW,CAAC;EACZ,WAAW,CAAC;EACZ,kBAAkB,CAAC;EACnB,iBAAiB,CAAC;EAClB,iBAAiB,CAAC;EAClB,WAAW,CAAC;EACZ,kBAAkB,CAAC;EACnB,YAAY,CAAC;EACb,UAAU,CAAC;CACb;AACF;AAEA,MAAM,kBAAkB,KAAa,QAAsB;CACzD,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,MAAA,SACvC,MAAM,IAAI,mBAAmB,iBAAiB,IAAI,oBAAoB,QAAQ,EAAE;CAElF,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,MAAA,OACvC,MAAM,IAAI,mBAAmB,iBAAiB,IAAI,oBAAoB,QAAQ,EAAE;AAEpF;;AAGA,SAAgB,QAAQ,IAAe,KAAa,KAA+B;CACjF,OAAO,GAAG,KAAK,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG;AAClC;;;;;AAMA,SAAgB,QAAQ,IAAe,KAAa,KAAa,QAAmB,MAAM,SAAwB;CAChH,IAAI,SAAS,GAAG,KAAK,IAAI,GAAG;CAC5B,IAAI,OAAO,QAAQ,IAAI,GAAG;CAC1B,IAAI,SAAS,KAAA,GAAW;EAGtB,OAAO,SAAS,KAAK,KAAK,OAAO,WAAW,CAAC;EAC7C,IAAI,WAAW,KAAA,GAAW;GACxB,yBAAS,IAAI,IAAkB;GAC/B,GAAG,KAAK,IAAI,KAAK,MAAM;EACzB;EACA,OAAO,IAAI,KAAK,IAAI;CACtB,OAAO;EACL,KAAK,QAAQ;EACb,IAAI,YAAY,KAAA,GAAW,KAAK,UAAU;CAC5C;CACA,IAAI,MAAM,GAAG,kBAAkB,GAAG,mBAAmB;CACrD,OAAO;AACT;;AAGA,SAAgB,WAAW,IAAe,KAAa,KAAmB;CACxE,MAAM,SAAS,GAAG,KAAK,IAAI,GAAG;CAC9B,IAAI,WAAW,KAAA,GAAW;CAC1B,OAAO,OAAO,GAAG;CACjB,IAAI,OAAO,SAAS,GAAG,GAAG,KAAK,OAAO,GAAG;AAC3C;;;;;;AAOA,SAAgB,WAAW,IAAe,OAAuB;CAC/D,MAAM,EAAE,QAAQ,QAAQ,QAAQ,WAAW,WAAW,KAAK;CAC3D,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAAK;EACrC,MAAM,SAAS,GAAG,KAAK,IAAI,CAAC;EAC5B,IAAI,CAAC,QAAQ;EACb,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAChC,IAAI,OAAO,OAAO,CAAC,GAAG;EAExB,IAAI,OAAO,SAAS,GAAG,GAAG,KAAK,OAAO,CAAC;CACzC;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,cAAc,IAAuB;CACnD,IAAI,IAAI;CACR,KAAK,MAAM,UAAU,GAAG,KAAK,OAAO,GAAG,KAAK,OAAO;CACnD,GAAG,KAAK,MAAM;CACd,GAAG,mBAAmB;CACtB,OAAO;AACT;;;;;;AAOA,SAAgB,UAAU,IAAe,QAAsD;CAC7F,MAAM,MAAM,GAAG,mBAAmB;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,OAAO;EACrB,IAAI,UAAU,KAAA,KAAa,UAAU,MAAM;EAC3C,QAAQ,IAAI,KAAK,IAAI,GAAG,KAAK;CAC/B;CAGA,GAAG,mBAAmB;CACtB,OAAO;AACT;;;;;;;;;AAUA,SAAgB,WACd,IACA,MACuC;CACvC,MAAM,WAAW,GAAG,mBAAmB;CACvC,IAAI,KAAK,WAAW,GAClB,OAAO;EAAE;EAAU,SAAS,WAAW;CAAE;CAE3C,IAAI,UAAU,WAAW;CACzB,KAAK,MAAM,OAAO,MAChB,UAAU,UAAU,IAAI,GAAG;CAE7B,OAAO;EAAE;EAAU;CAAQ;AAC7B;;;;;;;;;;;;;;;AAgBA,SAAgB,WACd,IACA,UACA,QACgF;CAChF,IAAI,OAAO,WAAW,GAAG,OAAO,KAAA;CAChC,MAAM,EAAE,KAAK,UAAU,KAAK,aAAa,kBAAkB,QAAQ;CACnE,IAAI,SAAS;CACb,IAAI,SAAS;CACb,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,MAAM,OAAO;EACnB,IAAI,QAAQ,KAAA,GAAW;EACvB,MAAM,IAAI,WAAW;EACrB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;GACnC,MAAM,IAAI,IAAI;GACd,IAAI,MAAM,KAAA,KAAa,MAAM,MAAM;GACnC,MAAM,IAAI,WAAW;GACrB,QAAQ,IAAI,GAAG,GAAG,CAAC;GACnB,IAAI,IAAI,QAAQ,SAAS;EAC3B;EACA,IAAI,IAAI,QAAQ,SAAS;CAC3B;CACA,OAAO;EAAE,QAAQ;EAAU;EAAQ,QAAQ;EAAU;CAAO;AAC9D;;;;;;;;;;;;;;;;AAwBA,UAAiB,SAAS,IAAe,OAAwB,CAAC,GAA2C;CAC3G,MAAM,EAAE,SAAS,GAAG,SAAS,UAAU,EAAE,GAAG,SAAS,GAAG,SAAS,UAAU,EAAE,MAAM;CACnF,IAAI,SAAS,UAAU,SAAS,QAAQ;CACxC,MAAM,QAAQ,SAAS,SAAS;CAChC,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAAK;EACrC,MAAM,SAAS,GAAG,KAAK,IAAI,CAAC;EAG5B,MAAM,MAA4B,IAAI,MAAM,KAAK,CAAC,CAAC,KAAK,KAAA,CAAS;EACjE,IAAI,WAAW,KAAA,GACb,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAAK;GACrC,MAAM,OAAO,OAAO,IAAI,CAAC;GACzB,IAAI,SAAS,KAAA,GAAW,IAAI,IAAI,UAAU;EAC5C;EAEF,MAAM;CACR;AACF;;;;;;AAOA,UAAiB,WAAW,IAAe,OAAwB,CAAC,GAAkC;CACpG,KAAK,MAAM,OAAO,SAAS,IAAI,IAAI,GACjC,MAAM,IAAI,KAAK,MAAO,MAAM,KAAA,IAAY,OAAO,EAAE,KAAM;AAE3D;;;;;;;AAQA,UAAiB,UAAU,IAAe,OAAwB,CAAC,GAA2B;CAC5F,KAAK,MAAM,OAAO,SAAS,IAAI,IAAI,GACjC,KAAK,MAAM,QAAQ,KACjB,IAAI,SAAS,KAAA,GAAW,MAAM;AAGpC;;AAGA,SAAgB,UAAU,IAAuB;CAC/C,IAAI,IAAI;CACR,KAAK,MAAM,KAAK,GAAG,KAAK,KAAK,GAAG,IAAI,IAAI,GAAG,IAAI;CAC/C,OAAO;AACT;;AAGA,SAAgB,UAAU,IAAuB;CAC/C,IAAI,IAAI;CACR,KAAK,MAAM,UAAU,GAAG,KAAK,OAAO,GAClC,KAAK,MAAM,KAAK,OAAO,KAAK,GAAG,IAAI,IAAI,GAAG,IAAI;CAEhD,OAAO;AACT;;;;;;;AAQA,SAAgB,uBAAuB,IAAyB;CAC9D,MAAM,MAAgB,CAAC;CACvB,KAAK,MAAM,CAAC,GAAG,WAAW,GAAG,MAC3B,IAAI,OAAO,OAAO,GAAG,IAAI,KAAK,CAAC;CAEjC,OAAO,IAAI,MAAM,GAAG,MAAM,IAAI,CAAC;AACjC;;;;;;AAOA,SAAgB,0BAA0B,IAAyB;CACjE,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,UAAU,GAAG,KAAK,OAAO,GAClC,KAAK,MAAM,KAAK,OAAO,KAAK,GAAG,KAAK,IAAI,CAAC;CAE3C,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;AACvC;;;;;;AAkCA,SAAgB,kBAAkB,GAA8D;CAC9F,IAAI,MAAM,MAAM,OAAO;CACvB,IAAI,OAAO,MAAM,UAAU,OAAO;CAClC,IAAI,OAAO,MAAM,UAAU,OAAO;CAClC,IAAI,OAAO,MAAM,WAAW,OAAO;CACnC,IAAI,aAAa,MAAM,OAAO;CAC9B,MAAM,OAAQ,EAAwB;CACtC,IAAI,SAAS,YAAY,OAAO;CAChC,IAAI,SAAS,SAAS,OAAO;CAC7B,IAAI,SAAS,aAAa,OAAO;CAEjC,OAAO;AACT;AAEA,SAAgB,iBAAiB,IAAkC;CACjE,MAAM,MAAyB;EAC7B,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,MAAM;EACN,UAAU;EACV,OAAO;EACP,aAAa;EACb,SAAS;CACX;CACA,KAAK,MAAM,QAAQ,UAAU,EAAE,GAC7B,IAAI,kBAAkB,KAAK,KAAK,EAAE;CAEpC,OAAO;AACT;;;;;;;AA+BA,SAAgB,iBAAiB,IAAwB;CACvD,KAAK,MAAM,QAAQ,UAAU,EAAE,GAC7B,IAAI,KAAK,UAAU,MAAM,OAAO;CAElC,OAAO;AACT;;;;;;;;;AAUA,SAAgB,qBACd,IACA,OAAiE,CAAC,GAC1D;CACR,MAAM,kBAAkB,KAAK,mBAAmB;CAChD,MAAM,kBAAkB,KAAK,mBAAmB;CAChD,IAAI,IAAI;CACR,KAAK,MAAM,QAAQ,UAAU,EAAE,GAAG;EAChC,MAAM,IAAI,KAAK;EACf,IAAI,MAAM,MAAM;EAChB,IAAI,OAAO,MAAM,YAAY,MAAM,MAAM;GACvC,MAAM,OAAQ,EAAwB;GACtC,IAAI,SAAS,aAAa,CAAC,iBAAiB;GAC5C,IAAI,SAAS,eAAe,CAAC,iBAAiB;EAChD;EACA;CACF;CACA,OAAO;AACT;;AAGA,SAAgB,WAAW,IAAuB;CAChD,IAAI,IAAI;CACR,KAAK,MAAM,UAAU,GAAG,KAAK,OAAO,GAAG,KAAK,OAAO;CACnD,OAAO;AACT;;;;;;AAOA,SAAgB,cACd,IACgF;CAChF,IAAI,SAAS,OAAO;CACpB,IAAI,SAAS;CACb,IAAI,SAAS,OAAO;CACpB,IAAI,SAAS;CACb,IAAI,UAAU;CACd,KAAK,MAAM,CAAC,GAAG,WAAW,GAAG,MAAM;EACjC,IAAI,OAAO,SAAS,GAAG;EACvB,IAAI,IAAI,QAAQ,SAAS;EACzB,IAAI,IAAI,QAAQ,SAAS;EACzB,KAAK,MAAM,KAAK,OAAO,KAAK,GAAG;GAC7B,IAAI,IAAI,QAAQ,SAAS;GACzB,IAAI,IAAI,QAAQ,SAAS;EAC3B;EACA,UAAU;CACZ;CACA,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,OAAO;EAAE;EAAQ;EAAQ;EAAQ;CAAO;AAC1C;;;;;;;AAuBA,UAAiB,UACf,IACA,WACwB;CACxB,MAAM,UAAU,CAAC,GAAG,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CACxD,KAAK,MAAM,KAAK,SAAS;EACvB,MAAM,SAAS,GAAG,KAAK,IAAI,CAAC;EAC5B,IAAI,CAAC,QAAQ;EACb,MAAM,OAAO,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;EACpD,KAAK,MAAM,KAAK,MAAM;GACpB,MAAM,OAAO,OAAO,IAAI,CAAC;GACzB,IAAI,SAAS,KAAA,KAAa,UAAU,IAAI,GAAG,MAAM;EACnD;CACF;AACF;;;;;;;AAuEA,UAAiB,gBAAgB,IAAe,OAAuC;CACrF,MAAM,EAAE,QAAQ,QAAQ,QAAQ,WAAW,WAAW,KAAK;CAC3D,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAAK;EACrC,MAAM,SAAS,GAAG,KAAK,IAAI,CAAC;EAC5B,IAAI,CAAC,QAAQ;EACb,KAAK,IAAI,MAAM,QAAQ,OAAO,QAAQ,OAAO;GAC3C,MAAM,OAAO,OAAO,IAAI,GAAG;GAC3B,IAAI,SAAS,KAAA,GAAW,MAAM;EAChC;CACF;AACF;;AAyDA,SAAgB,eAAe,IAAe,OAAe,OAAmB,SAAwB;CACtG,MAAM,IAAI,iCAAiC,KAAK,KAAK;CACrD,IAAI,MAAM,QAAQ,EAAE,OAAO,KAAA,KAAa,EAAE,OAAO,KAAA,GAC/C,MAAM,IAAI,mBAAmB,uCAAuC,MAAM,EAAE;CAE9E,MAAM,MAAM,sBAAsB,EAAE,EAAE;CAEtC,OAAO,QAAQ,IADH,OAAO,SAAS,EAAE,IAAI,EACb,GAAG,KAAK,OAAO,OAAO;AAC7C;;AAGA,SAAgB,eAAe,IAAe,OAAiC;CAC7E,MAAM,IAAI,iCAAiC,KAAK,KAAK;CACrD,IAAI,MAAM,QAAQ,EAAE,OAAO,KAAA,KAAa,EAAE,OAAO,KAAA,GAAW,OAAO,KAAA;CACnE,MAAM,MAAM,sBAAsB,EAAE,EAAE;CAEtC,OAAO,QAAQ,IADH,OAAO,SAAS,EAAE,IAAI,EACb,GAAG,GAAG;AAC7B;AAIA,MAAM,eAAe,eACnB,OAAO,eAAe,WAAW,WAAW,UAAU,IAAI;;;;;;;;AAS5D,SAAgB,WAAW,IAAe,YAA2C;CACnF,MAAM,QAAQ,YAAY,UAAU;CACpC,KAAK,MAAM,YAAY,GAAG,aAAa;EACrC,IAAI,cAAc,QAAQ,MAAM,cAAc,KAAK,GAAG,OAAO;EAC7D,IAAI,cAAc,UAAU,KAAK,GAC/B,MAAM,IAAI,mBACR,qBAAqB,cAAc,KAAK,EAAE,kCAAkC,cAAc,QAAQ,GACpG;CAEJ;CAEA,KAAK,IAAI,IAAI,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAC5C,KAAK,IAAI,IAAI,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK;EACjD,IAAI,MAAM,MAAM,UAAU,MAAM,MAAM,QAAQ;EAC9C,GAAG,KAAK,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC;EACxB,MAAM,MAAM,GAAG,KAAK,IAAI,CAAC;EACzB,IAAI,OAAO,IAAI,SAAS,GAAG,GAAG,KAAK,OAAO,CAAC;CAC7C;CAEF,GAAG,YAAY,KAAK,KAAK;CACzB,OAAO;AACT;;AAGA,SAAgB,aAAa,IAAe,YAAyC;CACnF,MAAM,SAAS,cAAc,YAAY,UAAU,CAAC;CACpD,MAAM,MAAM,GAAG,YAAY,WAAW,MAAM,cAAc,CAAC,MAAM,MAAM;CACvE,IAAI,MAAM,GAAG,OAAO;CACpB,GAAG,YAAY,OAAO,KAAK,CAAC;CAC5B,OAAO;AACT;;AAGA,SAAgB,eAAe,IAAyC;CACtE,OAAO,GAAG;AACZ;;AAGA,SAAgB,aAAa,IAAe,KAAa,KAAsB;CAC7E,KAAK,MAAM,SAAS,GAAG,aACrB,IAAI,kBAAkB,OAAO,KAAK,GAAG,GAAG,OAAO;CAEjD,OAAO;AACT;;;;;;AAOA,SAAgB,iBAAiB,IAAe,KAAa,KAAoC;CAC/F,KAAK,MAAM,SAAS,GAAG,aACrB,IAAI,kBAAkB,OAAO,KAAK,GAAG,GAAG,OAAO;AAGnD;;;;;;AAOA,SAAgB,eAAe,IAAe,KAAa,KAAsB;CAC/E,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,YAAY,QAAQ,KAAK;EAC9C,MAAM,IAAI,GAAG,YAAY;EACzB,IAAI,KAAK,kBAAkB,GAAG,KAAK,GAAG,GAAG;GACvC,GAAG,YAAY,OAAO,GAAG,CAAC;GAC1B,OAAO;EACT;CACF;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,sBAAsB,IAAuB;CAC3D,MAAM,IAAI,GAAG,YAAY;CACzB,GAAG,cAAc,CAAC;CAClB,OAAO;AACT;;AAKA,MAAM,qBAAqB,OAA6B;CACtD,IAAI,OAAO,GAAG,MAAM;CACpB,IAAI,CAAC,MAAM;EACT,OAAO,cAAc;EACrB,GAAG,MAAM,KAAK,IAAI;CACpB;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,eAAe,IAAe,YAAsC;CAClF,IAAI,eAAe,KAAA,GAAW;EAC5B,IAAI,GAAG,MAAM,IAAI,OAAO,GAAG,MAAM,EAAE,CAAC;EACpC;CACF;CACA,MAAM,OAAO,kBAAkB,EAAE;CACjC,KAAK,OAAO,eAAe,UAAU;AACvC;;AAGA,SAAgB,eAAe,IAAmC;CAChE,MAAM,OAAO,GAAG,MAAM;CACtB,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,OAAO,cAAc,IAAI;AAC3B;;AA0BA,SAAgB,YAAY,IAAe,MAAc,MAAoB;CAC3E,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GACpC,MAAM,IAAI,mBAAmB,qDAAqD,MAAM;CAE1F,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,GACpC,MAAM,IAAI,mBAAmB,qDAAqD,MAAM;CAE1F,eAAe,IAAI,GAAG,sBAAsB,OAAO,CAAC,IAAI,OAAO,GAAG;AACpE;;AA8BA,MAAM,yBAAyB,OAAmC;CAChE,IAAI,CAAC,GAAG,iBAAiB,GAAG,kBAAkB,oBAAoB;CAClE,OAAO,GAAG;AACZ;AAEA,MAAM,aAAa,UACjB,OAAO,UAAU,WAAW,UAAU,EAAE,KAAK,MAAM,CAAC,IAAI,UAAU,KAAK;;;;;AAMzE,SAAgB,iBAAiB,IAAe,OAAuC;CACrF,MAAM,IAAI,UAAU,KAAK;CACzB,sBAAsB,EAAE,CAAC,CAAC,WAAW;CACrC,OAAO;AACT;;;;;AAqCA,SAAgB,aAAa,IAAe,OAAqB;CAC/D,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,MAAM,QAAQ,KACpD,MAAM,IAAI,mBAAmB,4DAA4D,OAAO;CAElG,kBAAkB,EAAE,CAAC,CAAC,YAAY;AACpC;;AAGA,SAAgB,iBAAiB,IAAe,MAA0D;CACxG,kBAAkB,EAAE,CAAC,CAAC,OAAO;AAC/B;;;;;;;AA4CA,SAAgB,eACd,IACA,OACA,MACM;CACN,MAAM,EAAE,QAAQ,WAAW,WAAW,KAAK;CAC3C,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;EACjB,IAAI,CAAC,KAAK;EACV,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;GACnC,MAAM,IAAI,IAAI;GACd,IAAI,MAAM,QAAQ,MAAM,KAAA,GAAW;GACnC,QAAQ,IAAI,SAAS,GAAG,SAAS,GAAG,CAAC;EACvC;CACF;AACF;;;;;AAMA,SAAgB,aACd,IACA,OACA,OACM;CACN,MAAM,EAAE,QAAQ,QAAQ,QAAQ,WAAW,WAAW,KAAK;CAC3D,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAChC,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAAK;EACrC,IAAI,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC;EAChC,IAAI,CAAC,MAAM,OAAO,QAAQ,IAAI,GAAG,CAAC;EAClC,MAAM,MAAM,GAAG,CAAC;CAClB;AAEJ;;;;;;AAOA,SAAgB,eAAe,IAAe,OAAuC;CACnF,MAAM,EAAE,QAAQ,QAAQ,QAAQ,WAAW,WAAW,KAAK;CAC3D,MAAM,UAAkC,CAAC;CACzC,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAAK;EACrC,MAAM,SAAS,GAAG,KAAK,IAAI,CAAC;EAC5B,MAAM,MAA4B,CAAC;EACnC,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,KAAK;GACrC,MAAM,OAAO,QAAQ,IAAI,CAAC;GAC1B,IAAI,KAAK,OAAO,KAAK,QAAQ,IAAI;EACnC;EACA,QAAQ,KAAK,GAAG;CAClB;CACA,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,UACd,IACA,QACA,QACA,OAAiC,CAAC,GAC1B;CACR,MAAM,OAAO,KAAK,YAAY;CAC9B,MAAM,YAAY,SAAS;CAC3B,MAAM,MAAM,WAAW,MAAM;CAC7B,MAAM,MAAM,WAAW,MAAM;CAC7B,MAAM,KAAK,IAAI,SAAS,IAAI;CAC5B,MAAM,KAAK,IAAI,SAAS,IAAI;CAC5B,MAAM,eAAe,KAAK,IAAI,IAAI,SAAS,IAAI,QAAQ,IAAI,SAAS,IAAI,MAAM;CAC9E,MAAM,eAAe,KAAK,IAAI,IAAI,SAAS,IAAI,QAAQ,IAAI,SAAS,IAAI,MAAM;CAC9E,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,KAAK;EACtC,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,SAAS,CAAC;EACzC,IAAI,CAAC,QAAQ;EACb,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,KAAK;GACtC,MAAM,UAAU,OAAO,IAAI,IAAI,SAAS,CAAC;GACzC,IAAI,CAAC,SAAS;GAGd,MAAM,UAAU,QAAQ,MAFT,IAAI,SAAS,IAAI,IACjB,IAAI,SAAS,IAAI,IACc,QAAQ,OAAO,QAAQ,OAAO;GAO5E,IAAI,WAAW;IACb,IAAI,QAAQ,gBAAgB,KAAA,GAAW,QAAQ,cAAc,QAAQ;IACrE,IAAI,QAAQ,cAAc,KAAA,GAAW,QAAQ,YAAY,QAAQ;GACnE;GACA;EACF;CACF;CACA,OAAO;AACT;;;;;;;;;AAUA,SAAgB,UACd,IACA,QACA,QACA,OAAiC,CAAC,GAC1B;CACR,MAAM,OAAO,KAAK,YAAY;CAC9B,MAAM,YAAY,SAAS;CAC3B,MAAM,MAAM,WAAW,MAAM;CAC7B,MAAM,MAAM,WAAW,MAAM;CAC7B,MAAM,KAAK,IAAI,SAAS,IAAI;CAC5B,MAAM,KAAK,IAAI,SAAS,IAAI;CAC5B,MAAM,eAAe,KAAK,IAAI,IAAI,SAAS,IAAI,QAAQ,IAAI,SAAS,IAAI,MAAM;CAC9E,MAAM,eAAe,KAAK,IAAI,IAAI,SAAS,IAAI,QAAQ,IAAI,SAAS,IAAI,MAAM;CAG9E,MAAM,OAAwD,CAAC;CAC/D,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,KAAK;EACtC,MAAM,SAAS,GAAG,KAAK,IAAI,IAAI,SAAS,CAAC;EACzC,IAAI,CAAC,QAAQ;EACb,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,KAAK;GACtC,MAAM,UAAU,OAAO,IAAI,IAAI,SAAS,CAAC;GACzC,IAAI,CAAC,SAAS;GACd,KAAK,KAAK;IAAE,KAAK,IAAI,SAAS;IAAG,KAAK,IAAI,SAAS;IAAG,MAAM;GAAQ,CAAC;EACvE;CACF;CAGA,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,KAAK;EACtC,MAAM,SAAS,IAAI,SAAS;EAC5B,MAAM,SAAS,GAAG,KAAK,IAAI,MAAM;EACjC,IAAI,CAAC,QAAQ;EACb,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,KAAK,OAAO,OAAO,IAAI,SAAS,CAAC;EACpE,IAAI,OAAO,SAAS,GAAG,GAAG,KAAK,OAAO,MAAM;CAC9C;CAKA,KAAK,MAAM,SAAS,MAAM;EACxB,MAAM,EAAE,KAAK,KAAK,SAAS;EAG3B,MAAM,UAAU,QAAQ,MAFT,MAAM,IACN,MAAM,IACyB,KAAK,OAAO,KAAK,OAAO;EACtE,IAAI,WAAW;GACb,IAAI,KAAK,gBAAgB,KAAA,GAAW,QAAQ,cAAc,KAAK;GAC/D,IAAI,KAAK,cAAc,KAAA,GAAW,QAAQ,YAAY,KAAK;EAC7D;CACF;CACA,OAAO,KAAK;AACd;;;;;;AAiEA,SAAgB,cAAc,IAAe,KAAqB;CAChE,MAAM,SAAS,GAAG,KAAK,IAAI,GAAG;CAC9B,IAAI,CAAC,UAAU,OAAO,SAAS,GAAG,OAAO,CAAC;CAC1C,MAAM,aAAa,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAC1D,MAAM,MAAc,CAAC;CACrB,KAAK,MAAM,OAAO,YAAY;EAC5B,MAAM,OAAO,OAAO,IAAI,GAAG;EAC3B,IAAI,MAAM,IAAI,KAAK,IAAI;CACzB;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,iBAAiB,IAAe,KAAqB;CACnE,MAAM,aAAa,CAAC,GAAG,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAC3D,MAAM,MAAc,CAAC;CACrB,KAAK,MAAM,KAAK,YAAY;EAC1B,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,GAAG;EACpC,IAAI,MAAM,IAAI,KAAK,IAAI;CACzB;CACA,OAAO;AACT;;;;;;AASA,SAAgB,mBAAmB,IAAe,KAA0C;CAC1F,KAAK,MAAM,OAAO,GAAG,iBAAiB,OAAO,GAC3C,IAAI,OAAO,IAAI,OAAO,OAAO,IAAI,KAAK,OAAO;AAGjD;;;;;;AAOA,SAAgB,mBACd,IACA,KACA,MACiB;CACjB,eAAe,GAAG,GAAG;CAGrB,KAAK,MAAM,CAAC,KAAK,QAAQ,GAAG,kBAC1B,IAAI,OAAO,IAAI,OAAO,OAAO,IAAI,KAAK,GAAG,iBAAiB,OAAO,GAAG;CAEtE,MAAM,QAAQ,oBAAoB,KAAK,IAAI;CAC3C,GAAG,iBAAiB,IAAI,KAAK,KAAK;CAClC,OAAO;AACT;;AAGA,SAAgB,eAAe,IAAe,KAAa,OAAgC;CAEzF,OAAO,mBAAmB,IAAI,KAAK;EAAE,GADpB,mBAAmB,IAAI,GACO;EAAG;EAAO,aAAa;CAAK,CAAC;AAC9E;;AAGA,SAAgB,WAAW,IAAe,KAA8B;CAEtE,OAAO,mBAAmB,IAAI,KAAK;EAAE,GADpB,mBAAmB,IAAI,GACO;EAAG,QAAQ;CAAK,CAAC;AAClE;;;;;;AAOA,SAAgB,aAAa,IAAe,KAAmB;CAC7D,MAAM,WAAW,mBAAmB,IAAI,GAAG;CAC3C,IAAI,CAAC,UAAU;CACf,MAAM,EAAE,QAAQ,OAAO,GAAG,SAAS;CACnC,MAAM,EAAE,KAAK,MAAM,KAAK,MAAM,GAAG,gBAAgB;CACjD,IAAI,OAAO,KAAK,WAAW,CAAC,CAAC,WAAW,GACtC,GAAG,iBAAiB,OAAO,SAAS,GAAG;MAEvC,mBAAmB,IAAI,KAAK,WAAW;AAE3C;;AAGA,SAAgB,YAAY,IAAe,SAAiB,OAAqB;CAC/E,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,sCAAsC,QAAQ,IAAI,MAAM,EAAE;CAEzF,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK,WAAW,IAAI,CAAC;AACzD;;AAGA,SAAgB,cAAc,IAAe,SAAiB,OAAqB;CACjF,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,wCAAwC,QAAQ,IAAI,MAAM,EAAE;CAE3F,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK,aAAa,IAAI,CAAC;AAC3D;;;;;;AAOA,SAAgB,sBAAsB,IAAe,OAAiC;CACpF,IAAI,UAAU,KAAA,GAAW;EACvB,OAAQ,GAAuC;EAC/C;CACF;CACA,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GACrC,MAAM,IAAI,mBAAmB,mEAAmE,OAAO;CAEzG,GAAG,qBAAqB;AAC1B;;;;;;AAOA,SAAgB,oBAAoB,IAAe,QAAkC;CACnF,IAAI,WAAW,KAAA,GAAW;EACxB,OAAQ,GAAqC;EAC7C;CACF;CACA,IAAI,CAAC,OAAO,SAAS,MAAM,KAAK,SAAS,GACvC,MAAM,IAAI,mBAAmB,kEAAkE,QAAQ;CAEzG,GAAG,mBAAmB;AACxB;AAEA,MAAM,wBAAwB,UAAwB;CAEpD,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,GACnD,MAAM,IAAI,mBAAmB,kDAAkD,OAAO;AAE1F;;;;;;;AAQA,SAAgB,UAAU,IAAe,SAAiB,OAAe,QAAQ,GAAS;CACxF,qBAAqB,KAAK;CAC1B,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,iCAAiC,QAAQ,IAAI,MAAM,EAAE;CAEpF,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK;EACrC,MAAM,WAAW,gBAAgB,IAAI,CAAC,KAAK,CAAC;EAC5C,gBAAgB,IAAI,GAAG;GAAE,GAAG;GAAU,cAAc;EAAM,CAAC;CAC7D;AACF;;;;;AAMA,SAAgB,YAAY,IAAe,SAAiB,OAAqB;CAC/E,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,mCAAmC,QAAQ,IAAI,MAAM,EAAE;CAEtF,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK;EACrC,MAAM,WAAW,GAAG,cAAc,IAAI,CAAC;EACvC,IAAI,CAAC,UAAU;EACf,MAAM,EAAE,cAAc,OAAO,GAAG,SAAS;EACzC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,GAAG,GAAG,cAAc,OAAO,CAAC;OACxD,GAAG,cAAc,IAAI,GAAG,IAAI;CACnC;AACF;;;;;AAMA,SAAgB,aAAa,IAAe,SAAiB,OAAe,QAAQ,GAAS;CAC3F,qBAAqB,KAAK;CAC1B,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,uCAAuC,QAAQ,IAAI,MAAM,EAAE;CAE1F,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK;EACrC,MAAM,WAAW,mBAAmB,IAAI,CAAC;EACzC,mBAAmB,IAAI,GAAG;GAAE,GAAG;GAAU,cAAc;EAAM,CAAC;CAChE;AACF;;;;;AAMA,SAAgB,eAAe,IAAe,SAAiB,OAAqB;CAClF,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,yCAAyC,QAAQ,IAAI,MAAM,EAAE;CAE5F,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK;EACrC,MAAM,WAAW,mBAAmB,IAAI,CAAC;EACzC,IAAI,CAAC,UAAU;EACf,MAAM,EAAE,cAAc,OAAO,GAAG,SAAS;EAEzC,MAAM,EAAE,KAAK,MAAM,KAAK,MAAM,GAAG,gBAAgB;EACjD,IAAI,OAAO,KAAK,WAAW,CAAC,CAAC,WAAW,GAEtC,GAAG,iBAAiB,OAAO,SAAS,GAAG;OAEvC,mBAAmB,IAAI,GAAG,WAAW;CAEzC;AACF;;;;;;;AAQA,SAAgB,iBAAiB,IAAe,SAAiB,OAAqB;CACpF,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,wCAAwC,QAAQ,IAAI,MAAM,EAAE;CAE3F,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK;EACrC,MAAM,WAAW,gBAAgB,IAAI,CAAC,KAAK,CAAC;EAC5C,gBAAgB,IAAI,GAAG;GAAE,GAAG;GAAU,QAAQ;GAAM,WAAW;EAAK,CAAC;CACvE;AACF;;;;;AAMA,SAAgB,eAAe,IAAe,SAAiB,OAAqB;CAClF,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,sCAAsC,QAAQ,IAAI,MAAM,EAAE;CAEzF,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK;EACrC,MAAM,WAAW,GAAG,cAAc,IAAI,CAAC;EACvC,IAAI,CAAC,UAAU;EACf,MAAM,EAAE,QAAQ,IAAI,WAAW,IAAI,GAAG,SAAS;EAC/C,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,GAAG,GAAG,cAAc,OAAO,CAAC;OACxD,GAAG,cAAc,IAAI,GAAG,IAAI;CACnC;AACF;;;;;;AAOA,SAAgB,oBAAoB,IAAe,SAAiB,OAAqB;CACvF,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,8CAA8C,QAAQ,IAAI,MAAM,EAAE;CAEjG,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK;EACrC,MAAM,WAAW,mBAAmB,IAAI,CAAC;EACzC,mBAAmB,IAAI,GAAG;GAAE,GAAG;GAAU,QAAQ;GAAM,WAAW;EAAK,CAAC;CAC1E;AACF;;;;;AAMA,SAAgB,kBAAkB,IAAe,SAAiB,OAAqB;CACrF,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,4CAA4C,QAAQ,IAAI,MAAM,EAAE;CAE/F,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK;EACrC,MAAM,WAAW,mBAAmB,IAAI,CAAC;EACzC,IAAI,CAAC,UAAU;EACf,MAAM,EAAE,QAAQ,IAAI,WAAW,OAAO,GAAG,SAAS;EAClD,MAAM,EAAE,KAAK,MAAM,KAAK,MAAM,GAAG,gBAAgB;EACjD,IAAI,OAAO,KAAK,WAAW,CAAC,CAAC,WAAW,GACtC,GAAG,iBAAiB,OAAO,SAAS,GAAG;OAEvC,mBAAmB,IAAI,GAAG,WAAW;CAEzC;AACF;;;;;AAMA,MAAM,mBAAmB,MAAY,OAAgI;CACnK,MAAM,MAAM,kBAAkB,KAAK,KAAK,CAAC,CAAC;CAC1C,IAAI,CAAC,IAAI,OAAO;CAEhB,MAAM,SADK,GAAG,OAAO,QAAQ,KAAK,QACjB,EAAE,UAAU;CAK7B,OAAO,QAJM,GAAG,OAAO,MAAM,OACZ,EAAE,QAAQ,MAGN;AACvB;;;;;;;AAqDA,SAAgB,eACd,IACA,OAKI,CAAC,GACC;CACN,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,WAAW,KAAK,OAAO;CAC7B,MAAM,WAAW,KAAK,IAAI,KAAK,OAAO,IAAI,GAAG;CAC7C,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,UAAU,GAAG,KAAK,OAAO,GAClC,KAAK,MAAM,CAAC,KAAK,SAAS,QAAQ;EAChC,MAAM,MAAM,gBAAgB,MAAM,KAAK,QAAQ;EAE/C,IAAI,OADQ,OAAO,IAAI,GAAG,KAAK,IAChB,OAAO,IAAI,KAAK,GAAG;CACpC;CAEF,KAAK,MAAM,CAAC,KAAK,MAAM,QAAQ;EAC7B,IAAI,MAAM,GAAG;EACb,eAAe,IAAI,KAAK,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,IAAI,OAAO,CAAC,CAAC;CAC7E;AACF;;;;;;;;AASA,SAAgB,gBACd,IACA,QACA,WAAW,GACL;CACN,IAAI,MAAM,QAAQ,MAAM,GACtB,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,IAAI,OAAO;EACjB,IAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,GAAG;EAClD,eAAe,IAAI,WAAW,GAAG,CAAC;CACpC;MAEA,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAgC,GAAG;EACrE,MAAM,MAAM,OAAO,SAAS,GAAG,EAAE;EACjC,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,GAAG;EACvC,IAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,GAAG;EAClD,eAAe,IAAI,KAAK,CAAC;CAC3B;AAEJ;;AAGA,SAAgB,gBAAgB,IAAe,KAAuC;CACpF,OAAO,GAAG,cAAc,IAAI,GAAG;AACjC;AAEA,SAAgB,gBAAgB,IAAe,KAAa,MAA2C;CACrG,eAAe,KAAK,CAAC;CACrB,MAAM,QAAQ,iBAAiB,IAAI;CACnC,GAAG,cAAc,IAAI,KAAK,KAAK;CAC/B,OAAO;AACT;;AAGA,SAAgB,aAAa,IAAe,KAAa,QAA8B;CAErF,OAAO,gBAAgB,IAAI,KAAK;EAAE,GADjB,gBAAgB,IAAI,GACO;EAAG;EAAQ,cAAc;CAAK,CAAC;AAC7E;;;;;;AAOA,SAAgB,cACd,IACA,SACA,WAAW,GACL;CACN,IAAI,MAAM,QAAQ,OAAO,GACvB,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,IAAI,QAAQ;EAClB,IAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,GAAG;EAClD,aAAa,IAAI,WAAW,GAAG,CAAC;CAClC;MAEA,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAAiC,GAAG;EACtE,MAAM,MAAM,OAAO,SAAS,GAAG,EAAE;EACjC,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,GAAG;EACvC,IAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,GAAG;EAClD,aAAa,IAAI,KAAK,CAAC;CACzB;AAEJ;;AAGA,SAAgB,QAAQ,IAAe,KAA2B;CAEhE,OAAO,gBAAgB,IAAI,KAAK;EAAE,GADjB,gBAAgB,IAAI,GACO;EAAG,QAAQ;CAAK,CAAC;AAC/D;;;;;AAMA,SAAgB,UAAU,IAAe,KAAmB;CAC1D,MAAM,WAAW,GAAG,cAAc,IAAI,GAAG;CACzC,IAAI,CAAC,UAAU;CACf,MAAM,EAAE,QAAQ,OAAO,GAAG,SAAS;CACnC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,GAAG,GAAG,cAAc,OAAO,GAAG;MAC1D,GAAG,cAAc,IAAI,KAAK,IAAI;AACrC;;AAGA,SAAgB,SAAS,IAAe,SAAiB,OAAqB;CAC5E,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,gCAAgC,QAAQ,IAAI,MAAM,EAAE;CAEnF,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK,QAAQ,IAAI,CAAC;AACtD;;AAGA,SAAgB,WAAW,IAAe,SAAiB,OAAqB;CAC9E,IAAI,CAAC,OAAO,UAAU,OAAO,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,UAAU,KAAK,QAAQ,SACnF,MAAM,IAAI,mBAAmB,kCAAkC,QAAQ,IAAI,MAAM,EAAE;CAErF,KAAK,IAAI,IAAI,SAAS,KAAK,OAAO,KAAK,UAAU,IAAI,CAAC;AACxD;;;;;;AASA,SAAgB,aACd,IACA,KACA,MACW;CACX,IAAI,KAAK,WAAW,KAAA,KAAa,KAAK,aAAa,KAAA,GACjD,MAAM,IAAI,mBAAmB,oDAAoD;CAEnF,gBAAgB,IAAI,GAAG;CACvB,MAAM,KAAK,cAAc;EAAE;EAAK,GAAG;CAAK,CAAC;CACzC,GAAG,WAAW,KAAK,EAAE;CACrB,OAAO;AACT;;AAGA,SAAgB,gBAAgB,IAAe,KAAsB;CACnE,MAAM,IAAI,GAAG,WAAW,WAAW,MAAM,EAAE,QAAQ,GAAG;CACtD,IAAI,IAAI,GAAG,OAAO;CAClB,GAAG,WAAW,OAAO,GAAG,CAAC;CACzB,OAAO;AACT;;AAGA,SAAgB,oBAAoB,IAAuB;CACzD,MAAM,IAAI,GAAG,WAAW;CACxB,GAAG,aAAa,CAAC;CACjB,OAAO;AACT;;AAQA,SAAgB,eAAe,IAAyC;CACtE,OAAO,GAAG;AACZ;;;;;;;AAQA,SAAgB,iBAAiB,IAAe,GAAgC;CAC9E,KAAK,MAAM,KAAK,GAAG,YAEjB,IAAI,kBADU,WAAW,EAAE,GACD,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO;AAGvD;;;;;;AAOA,SAAgB,eAAe,IAAe,GAAoC;CAChF,KAAK,MAAM,MAAM,GAAG,gBAElB,IAAI,kBADU,WAAW,GAAG,GACF,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO;AAGvD;;AAKA,SAAgB,kBAAkB,IAAe,IAAoC;CACnF,GAAG,gBAAgB,KAAK,EAAE;CAC1B,OAAO;AACT;;AAGA,SAAgB,sBAAsB,IAAe,WAAoD;CACvG,MAAM,SAAS,GAAG,gBAAgB;CAClC,GAAG,kBAAkB,GAAG,gBAAgB,QAAQ,OAAO,CAAC,UAAU,EAAE,CAAC;CACrE,OAAO,SAAS,GAAG,gBAAgB;AACrC;;AAGA,SAAgB,oBAAoB,IAA8C;CAChF,OAAO,GAAG;AACZ;;AAGA,SAAgB,yBAAyB,IAAuB;CAC9D,MAAM,IAAI,GAAG,gBAAgB;CAC7B,GAAG,kBAAkB,CAAC;CACtB,OAAO;AACT;;AAKA,SAAgB,cAAc,IAAe,QAAsC;CACjF,IAAI,WAAW,KAAA,GAAW;EACxB,OAAO,GAAG;EACV;CACF;CACA,GAAG,aAAa;AAClB;;AAGA,SAAgB,cAAc,IAAuC;CACnE,OAAO,GAAG;AACZ;;AAKA,SAAgB,SAAS,IAAe,OAAyC;CAC/E,GAAG,OAAO,KAAK,KAAK;CACpB,OAAO;AACT;;AAGA,SAAgB,SAAS,IAAe,aAAkD;CACxF,OAAO,GAAG,OAAO,MAAM,MAAM,EAAE,gBAAgB,WAAW;AAC5D;;AAGA,SAAgB,WAAW,IAA+C;CACxE,OAAO,GAAG;AACZ;;AAGA,SAAgB,YAAY,IAAe,aAA8B;CACvE,MAAM,IAAI,GAAG,OAAO,WAAW,MAAM,EAAE,gBAAgB,WAAW;CAClE,IAAI,IAAI,GAAG,OAAO;CAClB,GAAG,OAAO,OAAO,GAAG,CAAC;CACrB,OAAO;AACT;;AAGA,SAAgB,gBAAgB,IAAuB;CACrD,MAAM,IAAI,GAAG,OAAO;CACpB,GAAG,SAAS,CAAC;CACb,OAAO;AACT;;AAKA,SAAgB,WAAW,IAAe,MAAoE;CAC5G,MAAM,IAAI,GAAG,eAAe,WAAW,MAAM,EAAE,QAAQ,KAAK,GAAG;CAC/D,MAAM,IAAI,kBAAkB,IAAI;CAChC,IAAI,IAAI,GAAG,GAAG,eAAe,KAAK,CAAC;MAC9B,GAAG,eAAe,KAAK;CAC5B,OAAO;AACT;;AAcA,SAAgB,aAAa,IAA6C;CACxE,OAAO,GAAG;AACZ;;AAGA,SAAgB,kBAAkB,IAAuB;CACvD,MAAM,IAAI,GAAG,eAAe;CAC5B,GAAG,iBAAiB,CAAC;CACrB,OAAO;AACT;;AAsDA,SAAgB,yBAAyB,IAAe,IAAkD;CACxG,GAAG,sBAAsB,KAAK,EAAE;CAChC,OAAO;AACT;;AAQA,SAAgB,+BAA+B,IAAuB;CACpE,MAAM,IAAI,GAAG,sBAAsB;CACnC,GAAG,wBAAwB,CAAC;CAC5B,OAAO;AACT;;AAKA,SAAgB,aAAa,IAAe,OAA6B;CACvE,GAAG,YAAY,KAAK,KAAK;CACzB,OAAO;AACT;;AAGA,SAAgB,kBAAkB,IAAe,WAA8C;CAC7F,MAAM,SAAS,GAAG,YAAY;CAC9B,GAAG,cAAc,GAAG,YAAY,QAAQ,MAAM,CAAC,UAAU,CAAC,CAAC;CAC3D,OAAO,SAAS,GAAG,YAAY;AACjC;;AAGA,SAAgB,gBAAgB,IAAe,IAAgC;CAC7E,GAAG,cAAc,KAAK,EAAE;CACxB,OAAO;AACT;;AAGA,SAAgB,oBAAoB,IAAe,WAAkD;CACnG,MAAM,SAAS,GAAG,cAAc;CAChC,GAAG,gBAAgB,GAAG,cAAc,QAAQ,OAAO,CAAC,UAAU,EAAE,CAAC;CACjE,OAAO,SAAS,GAAG,cAAc;AACnC"}