qvdjs 2.2.1 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/QvdErrors.js","../src/util/cellRules.js","../src/util/symbolBytes.js","../src/QvdDual.js","../src/util/optionTypes.js","../src/util/readOptions.js","../src/util/storedSymbols.js","../src/util/linkTarget.js","../src/util/validatePath.js","../src/util/ioErrors.js","../src/util/openChecked.js","../src/util/replaceFile.js","../src/util/bitUtils.js","../src/QvdFileWriter.js","../src/util/memoryUtils.js","../src/util/validationUtils.js","../src/util/symbolParser.js","../src/util/resolveSymbols.js","../src/QvdColumnTable.js","../src/QvdFileReader.js","../src/QvdFile.js","../src/QvdDataFrame.js","../src/QvdSymbol.js","../src/index.js","../src/util/qlikDate.js"],"names":["fs","path","assert","crypto","wait","refuse","held","QvdFileReader","xml","QvdColumnTable","reader","QvdFileWriter","QvdFile"],"mappings":"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","file":"index.js","sourcesContent":["// @ts-check\n\n/**\n * The name each of this module's classes reports, written out rather than read from the class.\n *\n * A class's own `name` is whatever the build left it: the CommonJS bundle of every release checked from\n * 0.6.2 to 0.11.0 gave these classes no name at all, so `error.name` was `''` for a `require`d qvdjs,\n * and a bundler minifying the source renames them. `error.name` is what callers match on, so it must\n * not depend on either.\n *\n * @type {Map<Function, string>}\n */\nconst ERROR_NAMES = new Map();\n\n/**\n * Base error class for all QVD-related errors.\n * Provides structured error information with error codes and context.\n */\nexport class QvdError extends Error {\n /**\n * Constructs a new QVD error.\n *\n * @param {string} message The error message.\n * @param {string} code The error code.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`, so a `cause` becomes `error.cause`: the\n * error this one reports, such as the operating system's refusal behind a `QvdIOError`.\n */\n constructor(message, code, context = {}, options = undefined) {\n super(message, options);\n // A caller's own subclass keeps its own name.\n this.name = ERROR_NAMES.get(new.target) ?? new.target.name;\n this.code = code;\n this.context = context;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when parsing a QVD file fails.\n * Used for issues during XML header parsing, symbol table parsing, or index table parsing.\n */\nexport class QvdParseError extends QvdError {\n /**\n * Constructs a new QVD parse error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_PARSE_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when input validation fails.\n * Used for invalid parameters, out of bounds access, or missing required data.\n */\nexport class QvdValidationError extends QvdError {\n /**\n * Constructs a new QVD validation error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_VALIDATION_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when the operating system refuses a file-system call made to read or write a QVD\n * file: a missing file, a directory where a file was expected, a permission error, and on Windows a\n * file another process has locked (`EBUSY`). Locks on Linux and macOS are advisory, so a locked file\n * there reads and writes without an error at all.\n *\n * `context.code` is the system code Node reported - `ENOENT`, `EISDIR`, `EACCES`, `EBUSY` and so\n * on - and `context.operation` the call that failed, as Node names it: `open`, `fstat`, `read`,\n * `write`, `ftruncate`, `fsync` and `close`, and from a write that replaces the file rather than\n * rewriting it, `fchmod` and `rename` as well. `context.file` is the resolved path the caller asked\n * for, even where the call that failed was made on the temporary file a write builds beside it;\n * `cause` is Node's own error, unchanged, so its `errno`, `syscall` and the path it names are there\n * too. On Windows a `rename` that reports `EPERM` or `EBUSY` usually means another program has the\n * destination open - Qlik Sense reading it, most often - and the previous file is untouched.\n *\n * `context.temporaryFile` appears on one of these and only one: a write that failed and could not\n * remove the file it was building either, which is the only way one is left behind while a process is\n * still running. It names that file, so a caller can remove it.\n *\n * One has neither `context.code` nor `cause`, though its `code` is `QVD_IO_ERROR` like every other's:\n * a write that stored nothing while the operating system reported no error. There is no system code\n * to carry, so `context.filePosition` says where the file stops.\n */\nexport class QvdIOError extends QvdError {\n /**\n * Constructs a new QVD IO error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_IO_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when a QVD file is corrupted or malformed.\n * Used for missing headers, invalid data structures, or corrupted data.\n */\nexport class QvdCorruptedError extends QvdError {\n /**\n * Constructs a new QVD corrupted error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_CORRUPTED_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when security violations occur.\n * Used for path traversal attempts, XXE attacks, or other security issues.\n *\n * A refused path says why in `context.reason`. `'outside_allowed_directory'` is a path that resolves\n * outside allowedDir, and `'null_byte'` one with a NUL in it. `'changed_after_check'` is a file that\n * was not the one the containment check approved by the time it was opened: `context.change` is\n * `'became_a_symlink'`; `'replaced'` for a different file at the same name; or `'appeared'` for a\n * read that found a file at a name the check found empty. Each, left alone, would have read or\n * written a file the check never saw, and on a sandbox shared with someone else it is what a symlink\n * race looks like. See `openChecked` for what it covers and what it cannot.\n */\nexport class QvdSecurityError extends QvdError {\n /**\n * Constructs a new QVD security error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_SECURITY_ERROR', context, options);\n }\n}\n\nERROR_NAMES.set(QvdError, 'QvdError');\nERROR_NAMES.set(QvdParseError, 'QvdParseError');\nERROR_NAMES.set(QvdValidationError, 'QvdValidationError');\nERROR_NAMES.set(QvdIOError, 'QvdIOError');\nERROR_NAMES.set(QvdCorruptedError, 'QvdCorruptedError');\nERROR_NAMES.set(QvdSecurityError, 'QvdSecurityError');\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * What a QVD symbol can hold, said once.\n *\n * Only the writer used to apply these rules. It defined the int32 range, to choose between an int\n * and a double, and refused NaN, the infinities and a string containing NUL. `QvdSymbol` checked\n * nothing: the RangeError from Node's `writeInt32LE` was its only range check, and it wrote a NUL\n * whole - so the same value could be refused by one and written by the other. Everything that\n * decides whether a number or a text can be stored now reads it from here, and throws from here.\n */\n\n/** Lower bound of the integer a type 1 or type 5 symbol holds. */\nexport const INT32_MIN = -2147483648;\n\n/** Upper bound of the integer a type 1 or type 5 symbol holds. */\nexport const INT32_MAX = 2147483647;\n\n/** Terminates a text in the symbol table, so a stored text cannot contain one. */\nexport const NUL = String.fromCharCode(0);\n\n/**\n * Marks a `QvdDual`, from whichever copy of this library built it.\n *\n * `Symbol.for` rather than `Symbol()`, and a brand rather than `instanceof`, because a cell can come\n * from a different copy of the class than the one checking it: the CommonJS and ESM builds loaded in\n * one process, two installed copies of the package, a Jest module registry that has been reset, or a\n * vm realm. Each has its own `QvdDual`, and `instanceof` answers false across all of them.\n */\nexport const DUAL_BRAND = Symbol.for('qvdjs.QvdDual');\n\n/**\n * The dual value a cell holds, or null when it is not one.\n *\n * A dual is either a `QvdDual` - recognised by its brand, so one built by another copy of this\n * library counts - or a plain object whose own enumerable keys are exactly `number` and `text`. The\n * second form is what every clone of a `QvdDual` produces: `structuredClone`, `postMessage`,\n * `v8.serialize` and `JSON` all keep own enumerable data properties and drop the class, so a frame\n * sent to a worker and back writes the same duals it was read with.\n *\n * The shape is exact because a looser one writes the wrong file silently. An object that merely\n * *has* `number` and `text` - a record `{number, text, date}`, an array given the two properties, an\n * object that inherits them - is somebody's own data, and storing it as a dual would discard the rest\n * of it without a word. It is refused instead, and so is anything that is not a plain object - see\n * `isPlainObject` - so an object literal from a vm realm is accepted where `instanceof Object` would\n * refuse it.\n *\n * The halves are not type-checked here. The caller validates them, so that a refusal can say which\n * half is wrong rather than that the object is not a dual.\n *\n * @param {any} value Any value.\n * @return {{number: any, text: any}|null} The value itself when it is a dual, or null.\n */\nexport function asDual(value) {\n if (value === null || typeof value !== 'object') {\n return null;\n }\n\n try {\n if (value[DUAL_BRAND] === true) {\n return value;\n }\n\n if (!isPlainObject(value)) {\n return null;\n }\n\n const keys = Object.keys(value);\n\n return keys.length === 2 &&\n ((keys[0] === 'number' && keys[1] === 'text') || (keys[0] === 'text' && keys[1] === 'number'))\n ? value\n : null;\n } catch {\n // A revoked Proxy throws from every one of those operations. It is not a dual, and the refusal\n // that follows describes it without touching it again.\n return null;\n }\n}\n\n/**\n * Whether a value is a plain object: an object literal from any realm, or one with a null prototype.\n *\n * Tested as \"a prototype that is null, or whose own prototype is null\", which is what a realm's\n * `Object.prototype` is. An array, a class instance and an object made with `Object.create(other)` are\n * not plain, although an instance of an anonymous class and the last read their constructor name as\n * `Object` through the chain.\n *\n * @param {any} value The value.\n * @return {boolean} True for a plain object.\n * @throws {TypeError} For a revoked Proxy, from `Array.isArray` and `Object.getPrototypeOf`.\n */\nexport function isPlainObject(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || Object.getPrototypeOf(prototype) === null;\n}\n\n/**\n * Whether a text reads as a finite number.\n *\n * This is the rule `{coerceNumericStrings: true}` applies, and the one every read applied from #212 until\n * coercion became opt-in. The reader started from `!isNaN(Number(text))` and was narrowed twice.\n * `Number('')` and `Number(' ')` are 0, which turned every blank cell Qlik stored into a real zero, so\n * blank text is never numeric. And `Number.isFinite` rather than `!isNaN`, because JavaScript reads `E` as\n * an exponent: `Number('8E5597')` is Infinity, and that string is a LEGO colour code in this repository's\n * own `lego/colors.qvd`. A text whose numeric reading is not finite stays text.\n *\n * @param {string} text The text.\n * @return {boolean} True when the text reads as a finite number.\n */\nexport function isNumericText(text) {\n return text.trim() !== '' && Number.isFinite(Number(text));\n}\n\n/**\n * Whether a number is stored as a 32-bit integer rather than as a double.\n *\n * This is the rule Qlik follows, read off the files it wrote rather than chosen here: every numeric\n * symbol in the bundled Qlik files is an int exactly when its value is an integer inside the int32\n * range, whether it is a pure number or a dual. The kind follows the value, never the text.\n *\n * -0 is stored as the integer 0, because `Number.isInteger(-0)` is true and -0 is inside the range.\n * That is the cause, and not a Map folding the two together: a Map only merges 0 and -0 when both\n * occur in one column, and a column holding -0 alone is stored as 0 all the same. Qlik's engine\n * compares -0 equal to 0 and `Num()` shows it as 0.\n *\n * @param {number} value A finite number.\n * @return {boolean} True when the value is stored as an int symbol.\n */\nexport function isStoredAsInt(value) {\n return Number.isInteger(value) && value >= INT32_MIN && value <= INT32_MAX;\n}\n\n/**\n * Why a value cannot be stored as a number, or null when it can.\n *\n * @param {any} value The value.\n * @return {string|null} `'is a string, not a number'` and the like, `'is NaN'`, `'is Infinity'`,\n * `'is -Infinity'`, or null.\n */\nexport function numberProblem(value) {\n if (typeof value !== 'number') {\n return `is ${describeType(value)}, not a number`;\n }\n\n return Number.isFinite(value) ? null : `is ${String(value)}`;\n}\n\n/**\n * Why a value cannot be stored as a text, or null when it can.\n *\n * NUL is refused because it is what ends a text in the symbol table: a text containing one was\n * written whole, and the reader then took the character after it for the next symbol's type byte.\n *\n * An unpaired surrogate is refused because UTF-8 has no encoding for one. A JavaScript string is a\n * sequence of UTF-16 code units, and a code unit from U+D800 to U+DFFF is half of a character unless\n * a high one is followed by a low one. Node writes each half on its own as U+FFFD, the replacement\n * character, so `'\\uD800'` and `'\\uDFFF'` were written as the same three bytes: two different strings\n * became two symbols with one stored value, and neither read back as what was written.\n *\n * A string with both problems reports the NUL.\n *\n * @param {any} value The value.\n * @return {{reason: 'type'|'nul'|'surrogate', position?: number}|null} The problem, with the index of\n * the offending code unit where there is one, or null.\n */\nexport function textProblem(value) {\n if (typeof value !== 'string') {\n return {reason: 'type'};\n }\n\n // indexOf rather than includes: this runs once per distinct value on a table that may have\n // millions of them, and indexOf on a string primitive is the cheaper of the two.\n const position = value.indexOf(NUL);\n\n if (position !== -1) {\n return {reason: 'nul', position};\n }\n\n // isWellFormed is one native call for the whole string, so the scan for where the problem is runs\n // only for a string that is about to be refused.\n return value.isWellFormed() ? null : {reason: 'surrogate', position: unpairedSurrogateIndex(value)};\n}\n\n/**\n * The index of the first code unit in a string that is half of a surrogate pair without the other\n * half.\n *\n * @param {string} value A string that is not well formed.\n * @return {number} The index, or -1 when every surrogate is paired.\n */\nfunction unpairedSurrogateIndex(value) {\n for (let index = 0; index < value.length; index++) {\n const unit = value.charCodeAt(index);\n\n if (unit < 0xd800 || unit > 0xdfff) {\n continue;\n }\n\n // A high surrogate followed by a low one is one character: step over both. charCodeAt past the\n // end is NaN, which fails the comparison, so a high surrogate at the end is unpaired.\n const next = value.charCodeAt(index + 1);\n\n if (unit <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) {\n index++;\n continue;\n }\n\n return index;\n }\n\n return -1;\n}\n\n/**\n * Throws unless a value can be stored as a number.\n *\n * `subject` names the half being checked, as the message starts: `'The double of a symbol'` gives\n * \"The double of a symbol must be a finite number; got a string\". A cell is the exception, and is\n * checked with a null subject: it is already known to be a number, so all that can be wrong with it\n * is NaN or an infinity, and the message for that has been quoted to callers since the writer first\n * refused it.\n *\n * @param {any} value The value.\n * @param {string|null} subject What the value is, capitalised; null for a cell.\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If the value is not a finite number.\n */\nexport function checkNumber(value, subject, context) {\n if (numberProblem(value) === null) {\n return;\n }\n\n if (subject === null && typeof value === 'number') {\n throw new QvdValidationError('NaN and Infinity cannot be stored in a QVD field', {\n ...context,\n provided: String(value),\n });\n }\n\n throw new QvdValidationError(`${subject ?? 'A number'} must be a finite number; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n}\n\n/**\n * Throws unless a value can be stored as a text.\n *\n * @param {any} value The value.\n * @param {string} subject What the value is, capitalised, as the message starts: `'A string value'`\n * gives \"A string value cannot contain a NUL character\".\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If the value is not a string, or holds a NUL or an unpaired surrogate,\n * which no stored text can; `context.position` is that code unit's index.\n */\nexport function checkText(value, subject, context) {\n const problem = textProblem(value);\n\n if (problem === null) {\n return;\n }\n\n if (problem.reason === 'type') {\n throw new QvdValidationError(`${subject} must be a string; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n }\n\n if (problem.reason === 'surrogate') {\n throw new QvdValidationError(`${subject} cannot contain an unpaired surrogate`, {\n ...context,\n position: problem.position,\n });\n }\n\n throw new QvdValidationError(`${subject} cannot contain a NUL character`, {...context, position: problem.position});\n}\n\n/**\n * The name of a value's constructor, read without letting the read throw.\n *\n * A getter, or a revoked Proxy, can throw from `value.constructor`, and an error message is the\n * wrong place to find that out: the caller would get that error instead of the one being built.\n *\n * @param {any} value An object.\n * @return {string|null} The name, or null when there is none to read.\n */\nexport function constructorName(value) {\n try {\n const name = value.constructor?.name;\n\n return typeof name === 'string' && name !== '' ? name : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Names a value's type the way a caller reading an error would.\n *\n * `typeof` alone says \"object\" for a Date, an array and a Map alike, which is the least useful thing\n * it could say in a message whose job is to tell somebody what to convert. The value is never\n * converted to a string along the way: an object's own conversion can throw, or say nothing about\n * what the object is.\n *\n * @param {any} value The value.\n * @return {string} `'a Date'`, `'an array'`, `'a plain object with keys a, b'`, `'a boolean'`,\n * `'NaN'`, and so on.\n */\nexport function describeType(value) {\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'number') {\n // A number that fails a number check is NaN or an infinity, and \"got a number\" would say nothing.\n return Number.isFinite(value) ? 'a number' : String(value);\n }\n\n if (typeof value === 'undefined') {\n return 'undefined';\n }\n\n if (typeof value !== 'object') {\n return `a ${typeof value}`;\n }\n\n let name;\n\n try {\n if (Array.isArray(value)) {\n return 'an array';\n }\n\n // '[object Date]' when there is no constructor name to read: a null prototype, a replaced\n // constructor property.\n name = constructorName(value) ?? Object.prototype.toString.call(value).slice(8, -1);\n\n if (name === 'Object') {\n // The name an object inheriting from another reads through its chain, too - from\n // `Object.create({number: 1, text: 'x'})`, or an instance of an anonymous class - and calling that\n // plain would contradict a message asking for one: \"metadata must be a plain object; got a plain\n // object\".\n if (!isPlainObject(value)) {\n return 'an object whose prototype is not Object.prototype';\n }\n\n const keys = Object.keys(value);\n\n if (keys.length === 0) {\n return 'a plain object';\n }\n\n // Capped, because the message is for a person and an object can have any number of keys.\n return `a plain object with keys ${keys.slice(0, 5).join(', ')}${keys.length > 5 ? ', ...' : ''}`;\n }\n } catch {\n // A revoked Proxy throws from Array.isArray itself.\n return 'an object';\n }\n\n // 'an Error', 'an Int32Array', but 'a Uint8Array': a leading U is read \"you\".\n return `${/^[aeio]/i.test(name) ? 'an' : 'a'} ${name}`;\n}\n","// @ts-check\n\nimport {isStoredAsInt} from './cellRules.js';\n\n/**\n * How one symbol is laid out in the symbol table, said once.\n *\n * | Kind | Bytes after the type byte |\n * | --- | --- |\n * | 1, int | int32, little-endian |\n * | 2, double | float64, little-endian |\n * | 4, string | UTF-8 text, then a NUL |\n * | 5, dual int | int32, then UTF-8 text and a NUL |\n * | 6, dual double | float64, then UTF-8 text and a NUL |\n *\n * Nothing here validates. A caller checks its values through `cellRules` first, and these\n * functions encode what they are given.\n */\n\n/**\n * The kind a value is stored as.\n *\n * The number decides between int and double - through `isStoredAsInt`, which is Qlik's rule - and\n * the presence of a text decides between pure and dual. Nothing else does: a text is never parsed\n * to choose a kind.\n *\n * @param {number|null} number The numeric half, or null for a string.\n * @param {string|null} text The text, or null for a pure number.\n * @return {1|2|4|5|6} The type byte.\n */\nexport function kindOf(number, text) {\n if (number === null) {\n return 4;\n }\n\n if (isStoredAsInt(number)) {\n return text === null ? 1 : 5;\n }\n\n return text === null ? 2 : 6;\n}\n\n/**\n * The bytes one symbol takes, type byte and terminator included.\n *\n * @param {number} kind The type byte.\n * @param {number|null} number The numeric half, unused for kind 4.\n * @param {string|null} text The text, unused for kinds 1 and 2.\n * @return {number} The length in bytes.\n */\nexport function symbolByteLength(kind, number, text) {\n const numberBytes = kind === 1 || kind === 5 ? 4 : kind === 2 || kind === 6 ? 8 : 0;\n // @ts-ignore - a kind of 4, 5 or 6 carries a text\n const textBytes = kind >= 4 ? Buffer.byteLength(text, 'utf8') + 1 : 0;\n\n return 1 + numberBytes + textBytes;\n}\n\n/**\n * Encodes one symbol into a buffer.\n *\n * The buffer is expected to be sized with `symbolByteLength`, so every byte in the range is written:\n * a buffer from `Buffer.allocUnsafe` holds whatever memory it was given, and a byte skipped here\n * would put that memory into the file.\n *\n * @param {Buffer} buffer The buffer.\n * @param {number} offset Where the type byte goes.\n * @param {number} kind The type byte.\n * @param {number|null} number The numeric half, unused for kind 4.\n * @param {string|null} text The text, unused for kinds 1 and 2.\n * @return {number} The offset after the symbol.\n */\nexport function writeSymbol(buffer, offset, kind, number, text) {\n buffer[offset++] = kind;\n\n if (kind === 1 || kind === 5) {\n // @ts-ignore - kinds 1 and 5 carry a number\n offset = buffer.writeInt32LE(number, offset);\n } else if (kind === 2 || kind === 6) {\n // @ts-ignore - kinds 2 and 6 carry a number\n offset = buffer.writeDoubleLE(number, offset);\n }\n\n if (kind >= 4) {\n // @ts-ignore - kinds 4, 5 and 6 carry a text\n offset += buffer.write(text, offset, 'utf8');\n buffer[offset++] = 0;\n }\n\n return offset;\n}\n","// @ts-check\n\nimport {DUAL_BRAND, asDual, checkNumber, checkText} from './util/cellRules.js';\n\n/**\n * A Qlik dual value, holding both of its halves: a number, and the text Qlik displays for it.\n *\n * Qlik stores dates, timestamps and formatted numbers this way - the date `1756-01-01` is the number\n * -52593 with that text, and a fare of `4.50` is the number 4.5 with that text. To Qlik the value\n * *is* the number: it sums, sorts and compares by it, and the text belongs to how the field shows it.\n * That is why a read returns a dual as its number by default, and keeps the text with the frame so a\n * write puts it back. Read with `{duals: 'both'}` to get this object instead, for a cell that has to\n * carry both halves on its own - through a worker, or into another frame.\n *\n * It has no `valueOf` and no `toString`, and every implicit conversion throws a `TypeError`: `+`,\n * `-`, `<`, `==` against a primitive, a template literal, `String()`, `Number()`, `new Date()`,\n * `join()` and a default `sort()`. Each of those has to pick one half, and whichever it picked would\n * be wrong somewhere - `new Date(dual)` of a date's serial is a moment in January 1970, and a string\n * comparison of a fare's number is not a comparison of its text. Read `.number` or `.text` instead:\n *\n * ```js\n * const fare = new QvdDual(4.5, '4.50');\n * fare.number + 1; // 5.5\n * fare.text; // '4.50'\n * `${fare}`; // TypeError\n * ```\n *\n * It is plain data: `number` and `text` are own, enumerable, read-only properties, and the object is\n * frozen. So `structuredClone`, `postMessage`, `v8.serialize` and `JSON` all turn it into\n * `{number, text}`, and the writer accepts exactly that shape as a dual, from any copy of this\n * library. `===` compares identity, as for any object.\n */\nexport class QvdDual {\n /**\n * Constructs a dual value.\n *\n * The storage kind is not chosen here. The writer derives it from the number, as Qlik does: an\n * integer inside the int32 range is stored as a dual int, anything else as a dual double.\n *\n * @param {number} number The numeric half. Must be a finite number.\n * @param {string} text The text half. Must be a string with no NUL and no unpaired surrogate.\n * @throws {QvdValidationError} If either half cannot be stored in a QVD. The message names the half.\n */\n constructor(number, text) {\n checkNumber(number, 'The number of a dual value', {half: 'number'});\n checkText(text, 'The text of a dual value', {half: 'text'});\n\n defineHalves(this, number, text);\n }\n\n /**\n * Refuses every implicit conversion. See the class comment for why neither half is a safe answer.\n *\n * The hint JavaScript passes is not used: `'number'`, `'string'` and `'default'` say which\n * conversion ran, not which half the caller meant, and the fix is the same for all three.\n *\n * @return {never}\n * @throws {TypeError} Always.\n */\n [Symbol.toPrimitive]() {\n throw new TypeError(\n `A QvdDual holds two values, ${this.number} and ${JSON.stringify(this.text)}; use .number or .text`,\n );\n }\n\n /**\n * Both halves, so `JSON.stringify` loses neither - and produces the shape the writer accepts back.\n *\n * @return {{number: number, text: string}} The dual as a plain object.\n */\n toJSON() {\n return {number: this.number, text: this.text};\n }\n\n /**\n * How Node's `util.inspect` and `console.log` show a dual.\n *\n * @return {string} For example `QvdDual(4.5, \"4.50\")`.\n */\n [Symbol.for('nodejs.util.inspect.custom')]() {\n return `QvdDual(${this.number}, ${JSON.stringify(this.text)})`;\n }\n\n /** @return {string} `'QvdDual'`, for `Object.prototype.toString`. */\n get [Symbol.toStringTag]() {\n return 'QvdDual';\n }\n\n /**\n * Whether a value is a dual cell: a `QvdDual` from any copy of this library, or a plain object whose\n * own enumerable keys are exactly `number` and `text`, which is what a clone of one becomes.\n *\n * Recognition only. The halves are checked when the value is written.\n *\n * @param {any} value Any value.\n * @return {boolean} True for a dual cell.\n */\n static isDual(value) {\n return asDual(value) !== null;\n }\n}\n\n// On the prototype and not enumerable, so it is never copied: a clone is recognised by its shape,\n// and a copy of this class loaded elsewhere by the same key.\nObject.defineProperty(QvdDual.prototype, DUAL_BRAND, {value: true});\n\n/**\n * Defines a dual's halves as own, enumerable, read-only properties and freezes it.\n *\n * Own and enumerable is the point: those are the properties every clone keeps. A getter on the\n * prototype would clone to `{}`.\n *\n * @param {object} target The object being built.\n * @param {number} number The numeric half.\n * @param {string} text The text half.\n */\nfunction defineHalves(target, number, text) {\n Object.defineProperties(target, {\n number: {value: number, enumerable: true},\n text: {value: text, enumerable: true},\n });\n\n Object.freeze(target);\n}\n\n/**\n * A `QvdDual` for a symbol read from a file, taken as stored.\n *\n * Not validated, because a read reports what the file holds: a damaged file's NaN double reads as\n * NaN, and the writer refuses it if anyone stores it again. Built without calling the constructor\n * rather than by setting a flag the constructor reads, so no state outlives the call - a flag left\n * set by a call that threw would have switched validation off for the next `new QvdDual`.\n *\n * @param {number} number The stored int or double.\n * @param {string} text The stored text.\n * @return {QvdDual} A frozen dual.\n */\nexport function dualFromSymbol(number, text) {\n const dual = Object.create(QvdDual.prototype);\n\n defineHalves(dual, number, text);\n\n return dual;\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Checks an option that is a boolean and nothing else.\n *\n * A truthy string is the reason this refuses rather than coerces: `{atomic: 'false'}` would switch on\n * exactly what the caller asked to switch off, and a write that replaces the file where one was asked\n * to rewrite it - or the other way round - is not something they would find out about until it\n * mattered. The same goes for `{coerceNumericStrings: 1}`, which is where the rule started.\n *\n * `undefined` and `null` both mean \"nothing was said\", and `whenUnset` decides what that means. The\n * two callers read it differently on purpose: a read's `coerceNumericStrings` is off unless asked\n * for, while a write's `atomic` and `fsync` are on unless refused, because a null out of optional\n * configuration or a JSON round trip must not quietly become the way that loses the previous file.\n * `validatePath` reads a null `allowedDir` as the working directory for the same reason.\n *\n * Both callers get the same message and the same context, which is what this exists for: two copies\n * of the rule agreed only for as long as somebody kept them in step.\n *\n * @param {any} value The option as passed.\n * @param {{option: string, file: string, whenUnset: boolean}} about The option's name, the file being\n * read or written, and what an unset option means.\n * @return {boolean} What the option says, or `whenUnset`.\n * @throws {QvdValidationError} If the value is neither a boolean nor unset.\n */\nexport function booleanOption(value, {option, file, whenUnset}) {\n if (value === undefined || value === null) {\n return whenUnset;\n }\n\n if (typeof value !== 'boolean') {\n throw new QvdValidationError(`${option} must be true or false`, {\n option,\n provided: value,\n type: typeof value,\n file,\n });\n }\n\n return value;\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {booleanOption} from './optionTypes.js';\n\n/**\n * A read's row window: where it starts, and how many rows it covers.\n *\n * @typedef {Object} QvdRowWindow\n * @property {number} offset File row the window starts at.\n * @property {number|null} limit Rows in the window, or null for \"to the end of the file\".\n */\n\n/**\n * Checks a value that has to be a non-negative integer.\n *\n * Every one of these ends up inside a `Math.min(value, totalRows)` somewhere downstream, which\n * accepts nonsense silently: a negative value yields a negative row count, NaN makes every\n * comparison false, and a fraction produces a fractional loop bound. Each returns a wrong or\n * empty frame rather than an error.\n *\n * @param {any} value The value to check.\n * @param {string} name The option's name, for the error.\n * @param {string} filePath The file being read, for the error.\n * @return {number} The value.\n * @throws {QvdValidationError} If it is not a non-negative integer.\n */\nexport function requireRowCount(value, name, filePath) {\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {\n throw new QvdValidationError(`${name} must be a non-negative integer`, {\n reason: 'option',\n option: name,\n value,\n provided: value,\n type: typeof value,\n file: filePath,\n });\n }\n\n return value;\n}\n\n/**\n * Normalises a row window from what a caller passed.\n *\n * `maxRows` and `limit` are the same number under two names, and this is the one place that is\n * decided. `maxRows` came first and every released version documents it; `limit` is the spelling\n * that reads correctly beside `offset`, because \"the maximum number of rows\" says nothing about\n * where they start. Neither is deprecated and neither is preferred by the code - they resolve to\n * the same field here, three lines apart, so they cannot drift.\n *\n * Passing both is refused rather than resolved. Any rule for picking a winner - last one wins,\n * the smaller one wins, they have to agree - is a rule a caller has to know, and getting it wrong\n * returns a plausible number of rows rather than an error.\n *\n * @param {number|null|undefined|{offset?: number, limit?: number|null, maxRows?: number|null}} window\n * The window, or a plain row count meaning \"the first N rows\", or null for all of them.\n * @param {string} filePath The file being read, for errors.\n * @return {QvdRowWindow} The normalised window.\n */\nexport function normaliseWindow(window, filePath) {\n if (window === null || window === undefined) {\n return {offset: 0, limit: null};\n }\n\n // The historical spelling: load(5) means the first five rows. Kept exactly, because it is the\n // signature every existing caller uses and `5` and `{offset: 0, limit: 5}` are the same read.\n if (typeof window === 'number') {\n return {offset: 0, limit: requireRowCount(window, 'maxRows', filePath)};\n }\n\n if (typeof window !== 'object' || Array.isArray(window)) {\n throw new QvdValidationError('The row window must be a number, null, or an {offset, limit} object', {\n reason: 'option',\n option: 'limit',\n value: window,\n provided: window,\n type: typeof window,\n file: filePath,\n });\n }\n\n const {offset, limit, maxRows} = window;\n const limitGiven = limit !== undefined && limit !== null;\n const maxRowsGiven = maxRows !== undefined && maxRows !== null;\n\n if (limitGiven && maxRowsGiven) {\n throw new QvdValidationError('maxRows and limit are two names for the same option; pass one of them, not both', {\n reason: 'option',\n option: 'limit',\n value: limit,\n maxRows,\n limit,\n file: filePath,\n });\n }\n\n return {\n offset: offset === undefined || offset === null ? 0 : requireRowCount(offset, 'offset', filePath),\n limit: limitGiven\n ? requireRowCount(limit, 'limit', filePath)\n : maxRowsGiven\n ? requireRowCount(maxRows, 'maxRows', filePath)\n : null,\n };\n}\n\n/**\n * Holds `chunkSize` to the one rule every caller applies: a positive whole number of rows.\n *\n * One definition rather than two. `iterate` and `checkRead` both need it, and the second copy had\n * already drifted - it carried `reason` and `option` in its context where the first did not, so the same\n * mistake was reported two ways depending on which entry point saw it.\n *\n * @param {any} chunkSize What the caller passed.\n * @param {string} filePath The file, for the error.\n * @return {number} The chunk size.\n * @throws {QvdValidationError} If it is not a positive whole number.\n */\nexport function requireChunkSize(chunkSize, filePath) {\n if (typeof chunkSize !== 'number' || !Number.isInteger(chunkSize) || chunkSize <= 0) {\n throw new QvdValidationError('chunkSize must be a positive integer', {\n reason: 'option',\n option: 'chunkSize',\n value: chunkSize,\n provided: chunkSize,\n type: typeof chunkSize,\n file: filePath,\n });\n }\n\n return chunkSize;\n}\n\n/**\n * Resolves a validated window against the rows a file actually declares.\n *\n * One place, because the answer is used for three different things - which bytes to read, which\n * records to decode, and what to charge the memory guard - and any two of them disagreeing is a\n * silent wrong answer rather than an error.\n *\n * The offset is clamped as well as the count. An offset past the end of the file leaves no rows,\n * which is not an error: it is what a paging loop needs in order to stop, the same way\n * `Array.prototype.slice` answers it. But carrying the unclamped offset forward would have the\n * byte arithmetic demand records the file never had - `{offset: 10_000_000}` on a 135-row file\n * asking for a 30MB read of a 7KB file, and reporting the file as truncated.\n *\n * @param {QvdRowWindow} window The validated window.\n * @param {number} totalRows Rows the file's header declares. An unusable value resolves to an\n * empty window, leaving the structural checks downstream to say what is really wrong with it.\n * @return {QvdRowWindow} The window as it applies to this file: `limit` is now a row count rather\n * than a maximum, and `offset` is inside the file.\n */\nexport function resolveWindow(window, totalRows) {\n const rows = Number.isSafeInteger(totalRows) && totalRows > 0 ? totalRows : 0;\n const offset = Math.min(window.offset, rows);\n\n return {\n offset,\n limit: Math.max(0, Math.min(window.limit === null ? Infinity : window.limit, rows - offset)),\n };\n}\n\n/**\n * Checks a requested field list against the fields a file actually has.\n *\n * Refuses an unknown name rather than dropping it. Returning three columns for a four-name\n * request is the failure shape this library keeps designing against - the caller gets a data\n * frame, the shape looks plausible, and the missing column is discovered somewhere else entirely.\n * A duplicate is refused for the same reason: two columns of one name make `at(row, name)` and\n * `select(name)` answer about the first and ignore the second.\n *\n * The order is the caller's, not the file's, because that is what `QvdDataFrame.select()` already\n * does - `select('b', 'a')` returns `[b, a]` - and one library should not have two answers to the\n * same question.\n *\n * @param {Array<any>} fields Every field header in the file, in file order.\n * @param {Array<string>|null} requested Field names the caller asked for, or null for all.\n * @param {string} filePath The file being read, for errors.\n * @return {Array<any>} The selected field headers, in the caller's order.\n * @throws {QvdValidationError} If a name is unknown, repeated, or the list is empty.\n */\nexport function selectFields(fields, requested, filePath) {\n if (requested === null || requested === undefined) {\n return fields;\n }\n\n if (!Array.isArray(requested)) {\n throw new QvdValidationError('fields must be an array of field names', {\n reason: 'option',\n option: 'fields',\n value: requested,\n provided: requested,\n type: typeof requested,\n file: filePath,\n });\n }\n\n const available = fields.map((/** @type {any} */ field) => field['FieldName']);\n\n // A projection of no columns is a frame of N empty rows, whose shape is [N, 0] and whose data\n // answers nothing. Refusing is more useful than returning it.\n if (requested.length === 0) {\n throw new QvdValidationError('fields must name at least one field', {\n reason: 'option',\n option: 'fields',\n value: requested,\n availableColumns: available,\n file: filePath,\n });\n }\n\n /** @type {Set<string>} */\n const seen = new Set();\n\n return requested.map((name) => {\n if (typeof name !== 'string') {\n throw new QvdValidationError('Field names must be strings', {\n reason: 'option',\n option: 'fields',\n value: name,\n provided: name,\n type: typeof name,\n availableColumns: available,\n file: filePath,\n });\n }\n\n if (seen.has(name)) {\n throw new QvdValidationError(`Field '${name}' is listed twice`, {\n reason: 'option',\n option: 'fields',\n value: name,\n column: name,\n fields: requested,\n file: filePath,\n });\n }\n\n seen.add(name);\n\n const index = available.indexOf(name);\n\n if (index === -1) {\n throw new QvdValidationError(`Column '${name}' does not exist`, {\n reason: 'option',\n option: 'fields',\n value: name,\n column: name,\n availableColumns: available,\n file: filePath,\n });\n }\n\n return fields[index];\n });\n}\n\n/** What a dual symbol can read back as. The first is the default. */\nconst DUAL_MODES = Object.freeze(['number', 'text', 'both']);\n\n/**\n * Checks the `duals` option.\n *\n * A dual is a number with the text Qlik displays for it: the date -52593 shown as `1756-01-01`, the\n * fare 4.5 shown as `4.50`. Qlik treats the value as its number - it sums, sorts and compares by it -\n * so `'number'` is the default, and the text is kept with the frame so a write puts it back.\n * `'text'` returns the text instead, and `'both'` a frozen `QvdDual` holding both halves.\n *\n * Refused rather than defaulted when unrecognised: a typo such as `'numbers'` falling back to the\n * default would look like it worked, and the first sign of the mistake would be somewhere else.\n *\n * @param {any} value The option as passed. `undefined` and null mean the default.\n * @param {string} filePath The file being read, for the error.\n * @return {'number'|'text'|'both'} The mode.\n * @throws {QvdValidationError} If the value is not one of the modes.\n */\nexport function normaliseDuals(value, filePath) {\n if (value === undefined || value === null) {\n return 'number';\n }\n\n if (!DUAL_MODES.includes(value)) {\n throw new QvdValidationError(`duals must be one of ${DUAL_MODES.map((mode) => `'${mode}'`).join(', ')}`, {\n reason: 'option',\n option: 'duals',\n value,\n provided: value,\n file: filePath,\n });\n }\n\n return value;\n}\n\n/**\n * Checks the `coerceNumericStrings` option.\n *\n * Off by default. A string symbol is a value stored with no number, and a read that turned the ones\n * spelled like numbers into numbers returned values the file does not hold: `Number()` accepts\n * leading zeros, exponents, hex prefixes and surrounding whitespace, so `'007'` read as 7 and `'0x10'`\n * as 16. On, it is that rule - see `isNumericText` - for callers who relied on it, and the original\n * text is kept in the frame's `storedSymbols`, so a write stores the string again.\n *\n * It applies to every cell a read would return as a string: a string symbol in every `duals` mode, and\n * a dual's text under `{duals: 'text'}`, which reads as the number the dual stores rather than as\n * `Number(text)`.\n *\n * A boolean and nothing else. A truthy string such as `'false'` switching it on would be the opposite\n * of what was asked, with no error to say so.\n *\n * @param {any} value The option as passed. `undefined` and null mean off.\n * @param {string} filePath The file being read, for the error.\n * @return {boolean} Whether to coerce.\n * @throws {QvdValidationError} If the value is not a boolean.\n */\nexport function normaliseCoerceNumericStrings(value, filePath) {\n return booleanOption(value, {option: 'coerceNumericStrings', file: filePath, whenUnset: false});\n}\n\n/**\n * The reader options out of a public `fromQvd`-style options object.\n *\n * Split out so that `QvdDataFrame.fromQvd`, `QvdDataFrame.iterate` and `QvdColumnTable.fromQvd`\n * cannot end up supporting three slightly different option sets. They are three answers to the\n * same file with the same knobs; only the shape of what comes back differs.\n *\n * @param {any} options The caller's options.\n * @return {Object} Options for the `QvdFileReader` constructor.\n */\nexport function readerOptionsFrom(options) {\n return {\n allowedDir: options.allowedDir,\n memorySafetyFactor: options.memorySafetyFactor,\n symbolFilteringThreshold: options.symbolFilteringThreshold,\n fields: options.fields === undefined ? null : options.fields,\n duals: options.duals,\n coerceNumericStrings: options.coerceNumericStrings,\n onProgress: options.onProgress,\n signal: options.signal,\n };\n}\n\n/**\n * The reader options a header-only read can use.\n *\n * A subset of `readerOptionsFrom`, and expressed here beside it rather than hand-built at the call\n * site, because the subset is the interesting part: it is what stops the two drifting silently.\n * `readMetadata` used to construct `{allowedDir}` inline, so `onProgress` and `signal` were\n * accepted by the caller, ignored by the reader, and documented as shared by every entry point -\n * three statements that only stayed consistent for as long as nobody checked.\n *\n * `offset`, `limit`, `maxRows`, `fields`, `duals` and `coerceNumericStrings` are absent because they mean\n * nothing here, not because they were forgotten: a read that stops at the XML header has no rows to\n * window and parses no field's symbols to skip or resolve. They are ignored rather than refused, so that\n * one options object can be passed to `readMetadata` and to a data read without the caller having to\n * strip it.\n *\n * @param {any} options The caller's options.\n * @return {Object} Options for the `QvdFileReader` constructor.\n */\nexport function metadataOptionsFrom(options) {\n return {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n signal: options.signal,\n };\n}\n\n/**\n * The row window out of a public `fromQvd`-style options object.\n *\n * @param {any} options The caller's options.\n * @return {{offset?: number, limit?: number|null, maxRows?: number|null}} The window, unvalidated\n * - `normaliseWindow` does that, once, inside the reader.\n */\nexport function windowFrom(options) {\n return {offset: options.offset, limit: options.limit, maxRows: options.maxRows};\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {checkNumber, checkText, describeType} from './cellRules.js';\n\n/**\n * The stored-symbol record: what a frame keeps so that the cells it shows write back as the symbols\n * they were read from.\n *\n * A cell shows one value. Usually that value is the whole symbol - a pure number, a pure string - but\n * not always: a dual read as its number has a text the cell does not show, a dual read as its text has\n * a number, and a string read as a number has the text it was spelled with. For each field that holds\n * such a symbol the record keeps one entry, and entry `i` says that a cell holding `values[i]` stands\n * for the stored symbol (`numbers[i]`, `texts[i]`):\n *\n * | `numbers[i]` | `texts[i]` | The stored symbol |\n * | --- | --- | --- |\n * | a number | a string | a dual |\n * | null | a string | a pure string - one read as a number |\n * | a number | null | a pure number, recorded because another symbol reads as the same value |\n *\n * The last row is what lets the writer see a collision: when two different symbols read as one value,\n * both are recorded, and the writer refuses that value rather than guess which symbol a cell meant.\n *\n * It is plain data - arrays of numbers, strings and nulls - so it survives `JSON`, `structuredClone`,\n * `postMessage` and `v8.serialize` whole, and a frame sent elsewhere can be rebuilt with `fromDict`.\n * It is frozen, because every frame derived from a read shares it: a change through one would change\n * what all of them write.\n *\n * @typedef {Object} StoredSymbolsEntry\n * @property {string} field The field the entry describes.\n * @property {ReadonlyArray<number|string>} values What a cell holds for each recorded symbol.\n * @property {ReadonlyArray<number|null>} numbers Each symbol's number, or null for a pure string.\n * @property {ReadonlyArray<string|null>} texts Each symbol's text, or null for a pure number.\n */\n\n/**\n * @typedef {ReadonlyArray<StoredSymbolsEntry>} StoredSymbols\n */\n\n/**\n * Where a reader leaves the record on the header object it returns.\n *\n * `Symbol.for`, so any copy of this library finds it. The property is not enumerable, so the header\n * still deep-equals the one `readMetadata` returns for the same file, and a caller who builds a frame\n * the way the architecture notes show - `new QvdDataFrame(data, columns, df.metadata)` - keeps the\n * record without knowing it exists.\n */\nexport const STORED_SYMBOLS = Symbol.for('qvdjs.storedSymbols');\n\n/**\n * Records this copy of the module has built or validated, so passing one on - to `head()`, `select()`,\n * a chunk of `iterate()` - costs nothing. A WeakSet, so it holds no record alive.\n *\n * @type {WeakSet<object>}\n */\nconst trusted = new WeakSet();\n\n/**\n * Freezes a record the reader built and marks it as needing no validation.\n *\n * A reader's record is taken as the file stores it. A damaged file's NaN double is recorded as NaN,\n * which validation would refuse: a read reports what is there, and the writer refuses the value if\n * anyone stores it again.\n *\n * @param {Array<StoredSymbolsEntry>} entries Entries whose arrays are already frozen.\n * @return {StoredSymbols} The record.\n */\nexport function trustStoredSymbols(entries) {\n const record = Object.freeze(entries);\n\n trusted.add(record);\n\n return record;\n}\n\n/**\n * Leaves a record on a header object, without making it part of what the header enumerates.\n *\n * @param {any} metadata The header object a read returns.\n * @param {StoredSymbols} record The record.\n */\nexport function attachStoredSymbols(metadata, record) {\n if (metadata !== null && typeof metadata === 'object' && Object.isExtensible(metadata)) {\n Object.defineProperty(metadata, STORED_SYMBOLS, {value: record, enumerable: false, configurable: true});\n }\n}\n\n/**\n * Throws a validation error about a record.\n *\n * @param {string} message The message.\n * @param {Object} context The context.\n * @return {never}\n * @throws {QvdValidationError} Always.\n */\nfunction refuse(message, context) {\n throw new QvdValidationError(message, context);\n}\n\n/**\n * A record checked, frozen and safe to write from, or null for none.\n *\n * Every check a writer relies on is made here, once, so a record typed by hand or rebuilt from JSON\n * can be refused with a message rather than producing a file. What it does *not* check is whether two\n * entries make a value ambiguous; the writer works that out for the values a column actually holds,\n * so a record merged from two reads is checked against the cells it is used with.\n *\n * @param {any} record The record, null or undefined.\n * @return {StoredSymbols|null} A frozen record - the same one when it was already trusted, otherwise\n * a frozen copy - or null.\n * @throws {QvdValidationError} If the record is not an array of well-formed entries.\n */\nexport function normaliseStoredSymbols(record) {\n if (record === null || record === undefined) {\n return null;\n }\n\n if (typeof record === 'object' && trusted.has(record)) {\n return record;\n }\n\n if (!Array.isArray(record)) {\n refuse(`storedSymbols must be an array of field entries; got ${describeType(record)}`, {\n option: 'storedSymbols',\n type: typeof record,\n });\n }\n\n /** @type {Set<string>} */\n const fields = new Set();\n\n const entries = record.map((entry, index) => {\n if (entry === null || typeof entry !== 'object' || Array.isArray(entry) || typeof entry.field !== 'string') {\n refuse('Each storedSymbols entry must be an object with a string field name', {entry: index});\n }\n\n const {field, values, numbers, texts} = entry;\n\n if (fields.has(field)) {\n refuse(`storedSymbols lists field '${field}' twice`, {field, entry: index});\n }\n\n fields.add(field);\n\n if (\n !Array.isArray(values) ||\n !Array.isArray(numbers) ||\n !Array.isArray(texts) ||\n values.length !== numbers.length ||\n values.length !== texts.length\n ) {\n refuse(`The values, numbers and texts of the storedSymbols entry for '${field}' must be arrays of one length`, {\n field,\n entry: index,\n });\n }\n\n for (let symbol = 0; symbol < values.length; symbol++) {\n const value = values[symbol];\n const number = numbers[symbol];\n const text = texts[symbol];\n const context = {field, symbol};\n\n if (typeof value !== 'number' && typeof value !== 'string') {\n refuse(`A stored symbol's value must be a number or a string; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n }\n\n if (number !== null) {\n checkNumber(number, \"A stored symbol's number\", context);\n }\n\n if (text !== null) {\n checkText(text, \"A stored symbol's text\", context);\n }\n\n // What each kind of symbol can be read as. A dual reads as one of its halves; a pure string as\n // itself or, coerced, as a number; a pure number only as itself. An entry that says otherwise\n // would write a symbol no read of it could have produced.\n const consistent =\n number !== null && text !== null\n ? sameValueZero(value, number) || value === text\n : number === null && text !== null\n ? value === text || (typeof value === 'number' && Number.isFinite(value))\n : number !== null && sameValueZero(value, number);\n\n if (!consistent) {\n refuse(\n number === null && text === null\n ? 'A stored symbol needs a number or a text'\n : \"A stored symbol's value must be its number or its text\",\n {...context, value, number, text},\n );\n }\n }\n\n return Object.freeze({\n field,\n values: Object.freeze(values.slice()),\n numbers: Object.freeze(numbers.slice()),\n texts: Object.freeze(texts.slice()),\n });\n });\n\n return trustStoredSymbols(entries);\n}\n\n/**\n * The entries of a record for some of its fields, sharing them rather than copying.\n *\n * @param {StoredSymbols|null} record The record.\n * @param {ReadonlyArray<string>} columns The fields to keep.\n * @return {StoredSymbols|null} The narrowed record: the same one when nothing is dropped, an empty one\n * when nothing is kept, and null only when there was none. Never null for a record, because a frame\n * given null takes the one a read left on its header, with entries for every field of the read.\n */\nexport function narrowStoredSymbols(record, columns) {\n if (record === null) {\n return null;\n }\n\n const kept = record.filter((entry) => columns.includes(entry.field));\n\n return kept.length === record.length ? record : trustStoredSymbols(kept);\n}\n\n/**\n * The entry for one field, or null.\n *\n * @param {StoredSymbols|null} record The record.\n * @param {string} field The field.\n * @return {StoredSymbolsEntry|null} The entry.\n */\nexport function storedSymbolsEntry(record, field) {\n if (record === null) {\n return null;\n }\n\n return record.find((entry) => entry.field === field) ?? null;\n}\n\n/**\n * Value-to-text maps for `textAt`, built on first use per entry. Weak, so an entry that is no longer\n * referenced takes its map with it.\n *\n * @type {WeakMap<StoredSymbolsEntry, Map<number|string, string>>}\n */\nconst firstTexts = new WeakMap();\n\n/**\n * Each value of a record entry, mapped to the text a cell holding it stands for.\n *\n * The text of the first symbol holding the value that has one. Symbols are in the order they appear\n * in the file, and a pure number recorded for a collision has no text, so a dual's text wins over it\n * whichever of the two the file stores first. A value no symbol gives a text is not in the map.\n *\n * Built from the last symbol to the first, so an earlier text overwrites a later one and each symbol\n * costs one write rather than a lookup and a write.\n *\n * @param {StoredSymbolsEntry} entry The field's entry.\n * @return {Map<number|string, string>} Value to text.\n */\nexport function firstTextByValue(entry) {\n /** @type {Map<number|string, string>} */\n const byValue = new Map();\n\n for (let index = entry.values.length - 1; index >= 0; index--) {\n const text = entry.texts[index];\n\n if (text !== null) {\n byValue.set(entry.values[index], text);\n }\n }\n\n return byValue;\n}\n\n/**\n * The text a cell stands for, according to a record entry - see `firstTextByValue`.\n *\n * @param {StoredSymbolsEntry} entry The field's entry.\n * @param {number|string} value The cell.\n * @return {string|null} The text, or null when the entry gives the value none.\n */\nexport function storedTextOf(entry, value) {\n let byValue = firstTexts.get(entry);\n\n if (byValue === undefined) {\n byValue = firstTextByValue(entry);\n firstTexts.set(entry, byValue);\n }\n\n return byValue.get(value) ?? null;\n}\n\n/**\n * `SameValueZero`, the equality a Map uses for its keys: `===`, except that NaN equals NaN.\n *\n * @param {any} a One value.\n * @param {any} b The other.\n * @return {boolean} Whether they are the same value.\n */\nexport function sameValueZero(a, b) {\n return a === b || (a !== a && b !== b);\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\n\n/**\n * How many symlinks one path may be followed through before the walk gives up.\n *\n * A chain of dangling links terminates only because the kernel answers ELOOP for a cycle rather\n * than ENOENT, and every caller here reaches this code only after the kernel has already answered\n * ENOENT for the same path. This is the belt to that brace: past this many hops the open() these\n * callers precede would answer ELOOP itself, so stopping costs nothing real, and the walk cannot\n * run away on a filesystem that reports a cycle some other way. 40 is Linux's own MAXSYMLINKS, the\n * most permissive of the platforms here.\n */\nexport const MAX_LINK_HOPS = 40;\n\n/**\n * What `readDanglingLink` returns for a name that is on disk and is not a symlink, so there is\n * nothing to follow.\n */\nexport const NOT_A_LINK = Symbol('not a link');\n\n/**\n * What `readDanglingLink` returns for a symlink whose target it could not read. Callers must decide\n * what that means for them rather than treating it as either of the other two answers: it is a link,\n * so it is not `NOT_A_LINK`, and where it points is unknown, so it is not a path.\n */\nexport const UNREADABLE_LINK = Symbol('unreadable link');\n\n/**\n * Follows one symlink whose target does not exist.\n *\n * `realpath()` answers ENOENT for two different things, and they need opposite treatment:\n *\n * - A name that is not on disk. Whoever asked is about to create it, and the name they gave is the\n * name that will be created.\n * - A symlink pointing at a name that is not on disk. The name *is* on disk - it is the link's\n * target that is missing - and an `open()` of the path follows the link and creates the file at\n * the target, wherever that is.\n *\n * Telling the two apart is what decides both whether a path is inside its sandbox and which file a\n * write replaces. `validatePath` answers both in one walk, and the writer and the reader open what\n * that walk found rather than resolving the path again - see `checkPath` there. The two questions\n * used to be answered by two walks through this one function, which kept their rules alike but still\n * let them reach different files when a link changed between the walks: #247.\n *\n * @param {string} target Path whose `realpath()` or `stat()` answered ENOENT or ENOTDIR.\n * @return {string|typeof NOT_A_LINK|typeof UNREADABLE_LINK} Where the link points, resolved against\n * its own directory, or one of the two sentinels above.\n */\nexport function readDanglingLink(target) {\n /** @type {import('fs').Stats} */\n let link;\n\n try {\n link = fs.lstatSync(target);\n } catch {\n // Not on disk under its own name either, or an ancestor is a file or a dangling link itself.\n // Nothing here to follow.\n return NOT_A_LINK;\n }\n\n if (!link.isSymbolicLink()) {\n // The name is on disk and is not a link, yet the caller's own call could not resolve it: the two\n // disagree, which on a quiet filesystem they cannot. What they can disagree about is a link\n // replaced between them. There is nothing here to follow either way.\n return NOT_A_LINK;\n }\n\n /** @type {string} */\n let destination;\n\n try {\n destination = fs.readlinkSync(target);\n } catch {\n return UNREADABLE_LINK;\n }\n\n if (path.isAbsolute(destination)) {\n return destination;\n }\n\n // A relative target is resolved against the directory the link *physically* lives in, which is\n // what the kernel does: by the time it reads the link it has already resolved every directory it\n // walked through. Resolving against the lexical parent instead is not a near-enough approximation,\n // it is an escape. Given an alias inside allowedDir pointing at a shallower directory inside it -\n // say `<allowed>/deep/sub/alias` -> `<allowed>` - a link reached as `.../alias/link.qvd` lives at\n // `<allowed>/link.qvd`, so `../outside/x` means `<outside>/x` to the kernel and\n // `<allowed>/deep/sub/outside/x` to path.dirname. The first is out of the sandbox and the second\n // is in it, so the check passed a path an in-place write then created outside allowedDir.\n //\n // A parent that cannot be canonicalised leaves the target unknown, which is not the same as there\n // being no link: saying so lets each caller refuse rather than guess.\n try {\n return path.resolve(fs.realpathSync(path.dirname(target)), destination);\n } catch {\n return UNREADABLE_LINK;\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport {QvdSecurityError, QvdValidationError} from '../QvdErrors.js';\nimport {MAX_LINK_HOPS, NOT_A_LINK, UNREADABLE_LINK, readDanglingLink} from './linkTarget.js';\n\n/**\n * Determines whether a resolved path is contained within a resolved base directory, using only\n * string comparison.\n *\n * This is the fallback for when the filesystem cannot answer the question - in practice, when\n * allowedDir does not exist. It cannot see through symlinks and has to guess at case\n * sensitivity, which is exactly why it is not the primary check.\n *\n * Uses path.relative() rather than a string prefix test, so that filesystem roots\n * ('/', 'C:\\', '\\\\server\\share\\') and base directories with a trailing separator are\n * handled correctly. A prefix test appends path.sep to the base, which produces '//'\n * for a root and therefore matches nothing.\n *\n * @param {string} resolvedBaseDir Absolute, resolved base directory.\n * @param {string} resolvedPath Absolute, resolved candidate path.\n * @return {boolean} True if the path is the base directory itself or lies beneath it.\n */\nfunction isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) {\n // Folding is applied on Windows only. It used to cover darwin as well, on the assumption that\n // macOS is always case-insensitive, but macOS supports case-sensitive APFS and HFS+ volumes on\n // which two names differing only in case are genuinely different directories - so folding there\n // let a sibling directory pass the check. The on-disk comparison below settles case correctly\n // by asking the filesystem, which is why this fallback no longer needs to guess for darwin.\n const isCaseInsensitiveFS = process.platform === 'win32';\n const base = isCaseInsensitiveFS ? resolvedBaseDir.toLowerCase() : resolvedBaseDir;\n const target = isCaseInsensitiveFS ? resolvedPath.toLowerCase() : resolvedPath;\n\n const relative = path.relative(base, target);\n\n // '' means the path IS the base directory. A relative path that starts with '..' escapes\n // the base, and an absolute result means the two are on different roots/drives.\n if (relative === '') {\n return true;\n }\n if (path.isAbsolute(relative)) {\n return false;\n }\n return relative !== '..' && !relative.startsWith(`..${path.sep}`);\n}\n\n/**\n * What resolveDeepestExisting returns for a path that must be refused outright rather than handed\n * to the lexical fallback.\n *\n * Falling back is safe for EACCES and ELOOP because the open() that follows fails for the same\n * reason, so letting the path through costs nothing. That argument does not hold for a symlink the\n * walk could not read: the open() would succeed, at whatever the link points at, while the lexical\n * test saw only the link's own name inside allowedDir.\n */\nconst REFUSED = Symbol('refused');\n\n/**\n * What resolveDeepestExisting found.\n *\n * @typedef {Object} DeepestExisting\n * @property {string} deepest Canonical path of the deepest existing ancestor: the target itself when\n * it exists.\n * @property {boolean} exists Whether `deepest` is the target itself rather than an ancestor of it.\n * @property {string} farEnd The name an open() of the target reaches: the target, or the far end of\n * the dangling symlinks it names. It is what a write creates when the target does not exist.\n */\n\n/**\n * Resolves the deepest ancestor of a path that actually exists, following symlinks.\n *\n * A path being written to does not exist yet, and neither may some of its parent directories, so\n * realpath() on the full path would simply fail. Walking up to the first component that does\n * exist gives the deepest point the filesystem can vouch for; anything below it is a name that\n * will be created inside that directory.\n *\n * A component that is a dangling symlink is followed rather than stepped over. See\n * readDanglingLink in ./linkTarget.js for why the difference is what decides whether a write stays\n * in the sandbox.\n *\n * It also reports where the path leads, and not only whether that is inside the sandbox, because\n * the reader and the writer open what this walk found rather than resolving the path a second time.\n * A second resolution is a second answer, and #247 was the reader and the writer each following a\n * symlink swapped in after the first one: the check approved one file and the open reached another.\n *\n * @param {string} target Absolute, lexically resolved path.\n * @return {DeepestExisting|null|typeof REFUSED} What the walk found, null if it could not be\n * determined, or REFUSED for a path that must not reach the lexical test.\n */\nfunction resolveDeepestExisting(target) {\n let current = target;\n let farEnd = target;\n let walkedUp = false;\n /** Whether a link was followed after the walk had started climbing - see below. */\n let followedWhileClimbing = false;\n let hops = 0;\n\n for (;;) {\n try {\n const deepest = fs.realpathSync(current);\n\n // A file that does not exist yet is created at the far end, and the far end is spelled through\n // the directory the walk just resolved: its canonical path, then whatever lay below it. So the\n // name is opened through directories this check resolved rather than through the path again - a\n // symlinked directory that existed at the check is not traversed a second time at the open. That\n // holds only where the walk reached this directory by climbing from the far end; a link followed\n // on the way up leaves the file's directory missing, so the open fails whatever is said here.\n const canonicalFarEnd =\n walkedUp && !followedWhileClimbing ? path.join(deepest, path.relative(current, farEnd)) : farEnd;\n\n return {deepest, exists: !walkedUp, farEnd: canonicalFarEnd};\n } catch (error) {\n const code = /** @type {{code?: string}} */ (error)?.code;\n\n // ENOENT: this component does not exist. ENOTDIR: an ancestor is a file, so nothing below\n // it can exist either. Both mean \"keep walking up\". Anything else (EACCES, ELOOP) means the\n // filesystem cannot answer, and the caller falls back to the lexical test - which is safe,\n // because an open() on the same path is about to fail for the same reason.\n if (code !== 'ENOENT' && code !== 'ENOTDIR') {\n return null;\n }\n\n // Unless the component is a dangling symlink, which answers ENOENT while being very much on\n // disk. Stepping up past it would judge the link's own name rather than its target.\n const followed = readDanglingLink(current);\n\n if (followed === UNREADABLE_LINK) {\n return REFUSED;\n }\n\n if (followed !== NOT_A_LINK) {\n if (++hops > MAX_LINK_HOPS) {\n return REFUSED;\n }\n\n current = followed;\n\n // Only a link at the end of the path moves the file. One met on the way up - a directory\n // that is a dangling link - leaves the file with no directory to be created in, so an\n // open() of it fails whatever this says, and the far end stays where it was.\n if (walkedUp) {\n followedWhileClimbing = true;\n } else {\n farEnd = followed;\n }\n\n continue;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n walkedUp = true;\n current = parent;\n }\n }\n}\n\n/**\n * Determines whether a path is contained within a base directory by asking the filesystem.\n *\n * Both sides are resolved through symlinks and then compared by identity - device and inode -\n * rather than by name, walking up from the target until the base is found or the root is reached.\n * That settles two questions a string comparison cannot:\n *\n * - Symlinks. A link inside allowedDir pointing outside it resolves to its target, so it is\n * rejected. A lexical check sees only the link's own name, still under allowedDir, and lets it\n * through - which meant arbitrary read via the reader and arbitrary overwrite via the writer.\n * - Dangling symlinks. A link whose target does not exist yet is followed to where it points\n * rather than resolved, because realpath() cannot tell that name from one that is simply absent.\n * Both answer ENOENT, and treating the link as absent judged its parent instead of its target -\n * which let an in-place write create the file outside allowedDir.\n * - Case. On a case-insensitive volume 'Qvd' and 'qvd' are one directory and share an inode; on a\n * case-sensitive volume they are two directories with different inodes. Comparing identity gets\n * both right without inferring anything from process.platform, which is what the old code did\n * and got wrong on case-sensitive macOS volumes.\n *\n * Identity is read with {bigint: true}, and that is load-bearing. On Windows the inode is the\n * 64-bit NTFS file ID, with the MFT record number in the low 48 bits and a reuse counter in the\n * high 16, so any record whose counter has reached 32 has an ID of 2^53 or more. As a Number that\n * loses its low bits, and two directories created one after the other - adjacent records with the\n * same counter - can round to the same value. The sibling then compares equal to the base, and\n * every path under it passes as contained, symlink or not. It is the likeliest explanation of CI\n * run 35339008309, where a Windows runner accepted every path under a sibling of allowedDir.\n *\n * A check on a path is only as good as the open that follows it, because the path can change in\n * between. So this also returns what it approved: the file an open of the path reaches, and that\n * file's identity when it exists. `openChecked` in ./openChecked.js opens exactly that file, refuses\n * a symlink swapped in at its name, and compares the descriptor it gets with this identity, which is\n * what #247 was missing. What no check made through Node's API can cover is a directory further up\n * the path swapped for a symlink: see `openChecked` for that residual, and why it remains.\n *\n * @param {string} resolvedBaseDir Absolute, lexically resolved base directory.\n * @param {string} resolvedPath Absolute, lexically resolved candidate path.\n * @return {{contained: boolean, target: string, stats: import('fs').BigIntStats|null}|null} Whether\n * the path is contained, the file an open of it reaches, and that file's stats if it exists - or\n * null when the filesystem could not answer.\n */\nfunction isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {\n /** @type {import('fs').BigIntStats} */\n let baseStat;\n\n try {\n // The base has to exist to be identified. If it does not, there is nothing on disk to compare\n // against and the lexical fallback is all that is left.\n baseStat = fs.statSync(fs.realpathSync(resolvedBaseDir), {bigint: true});\n } catch {\n return null;\n }\n\n const found = resolveDeepestExisting(resolvedPath);\n\n // A dangling symlink the walk could not read. The lexical fallback would judge the link's own\n // name, which is inside allowedDir, while the open() still went wherever the link points, so\n // there is nothing safe to fall back to.\n if (found === REFUSED) {\n return {contained: false, target: resolvedPath, stats: null};\n }\n\n if (found === null) {\n return null;\n }\n\n // An existing file is opened by its canonical path, whose last component is not a symlink - which\n // is what lets the open refuse one that appears there afterwards. A file that does not exist yet is\n // created at the far end of any dangling links, as an open() of the path itself would create it.\n const target = found.exists ? found.deepest : found.farEnd;\n /** @type {import('fs').BigIntStats|null} */\n let stats = null;\n let current = found.deepest;\n\n // realpathSync() returns a fully canonical path, so every ancestor of it is canonical too and\n // walking up with dirname() cannot step through a symlink.\n for (let first = true; ; first = false) {\n const ownIdentity = first && found.exists;\n let stat;\n try {\n // The file's own identity is read without following a link at its name. realpathSync() resolved\n // it a moment ago to a name whose last component was not a link, but a link can be swapped in\n // before this line, and stat would then record whatever it points at - outside allowedDir,\n // perhaps - as the file this check approved. An open that follows the same link, which is what\n // Windows does for want of O_NOFOLLOW, would then match that identity and be let through. lstat\n // records the link as the link it is, which no open of its target can match. Only the file\n // itself: the directories above it are compared as they always were.\n stat = ownIdentity ? fs.lstatSync(current, {bigint: true}) : fs.statSync(current, {bigint: true});\n } catch {\n return null;\n }\n\n // The first stat is of the file itself when it exists. It is kept from this walk rather than\n // taken again later, so the identity an open is held to is the identity this check approved.\n if (ownIdentity) {\n stats = stat;\n }\n\n // Both sides are BigInts, so this compares every bit of the ID rather than a rounded double.\n if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {\n return {contained: true, target, stats};\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return {contained: false, target, stats};\n }\n current = parent;\n }\n}\n\n/**\n * A path the containment check approved, and what it approved.\n *\n * @typedef {Object} CheckedPath\n * @property {string} path The lexically resolved path, which is what callers report: the path they\n * were given, made absolute.\n * @property {string} base The allowed directory the check was made against, resolved. Held so that a\n * later check of the same path is made against the same directory, whatever the working directory\n * has become since.\n * @property {string} target The file an open of the path reaches: its canonical path when it exists,\n * or the name a write would create. This, and not `path`, is what is opened.\n * @property {import('fs').BigIntStats|null} stats The target's stats as the check found them, or null\n * when it did not exist then. Its `dev` and `ino` are what the opened descriptor is compared with.\n * @property {boolean} onDisk Whether the filesystem decided containment. False when it could not -\n * allowedDir does not exist, or a component refused to resolve - and the lexical fallback did. The\n * target is then only the lexical path, so there is nothing for an open to be held to.\n */\n\n/**\n * Checks that a path stays inside the allowed directory, and says what it found there.\n *\n * Containment is decided by the filesystem wherever it can be: both paths are resolved through\n * symlinks and compared by device and inode. That covers symlink escapes and case sensitivity,\n * neither of which a string comparison can get right. When the base directory does not exist,\n * there is nothing to compare against and a lexical check is used instead.\n *\n * To permit access to an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on\n * Windows). There is deliberately no separate \"disable the check\" value: a null or empty\n * allowedDir falls back to the current working directory, so a caller that accidentally\n * passes one still gets the restriction rather than silently losing it.\n *\n * The answer is a path and the file it reaches, and the second half is the one that matters to the\n * reader and the writer: they open `target` through `openChecked`, which holds the open to what this\n * approved. Opening `path` instead would resolve it again, and a second resolution can reach a\n * different file from the first.\n *\n * @param {string} filePath The path to check.\n * @param {string|null} [allowedDir] Optional allowed directory path. Defaults to the current\n * working directory to prevent path traversal attacks.\n * @throws {QvdValidationError} If filePath is not a non-empty string, or allowedDir is not a\n * string, null or undefined.\n * @throws {QvdSecurityError} If path traversal is detected.\n * @return {CheckedPath} What was checked, and what it reaches.\n */\nexport function checkPath(filePath, allowedDir) {\n // Validate argument types up front, so callers get a typed error instead of a bare TypeError\n // from deep inside the function (e.g. 'filePath.includes is not a function').\n if (typeof filePath !== 'string' || filePath.length === 0) {\n throw new QvdValidationError('filePath must be a non-empty string', {\n provided: filePath,\n type: typeof filePath,\n });\n }\n\n if (allowedDir !== undefined && allowedDir !== null && typeof allowedDir !== 'string') {\n throw new QvdValidationError('allowedDir must be a string, null or undefined', {\n provided: allowedDir,\n type: typeof allowedDir,\n });\n }\n\n // Check for null bytes which can be used in path traversal attacks\n if (filePath.includes('\\0')) {\n throw new QvdSecurityError('Path traversal detected: Null byte in path', {\n path: filePath,\n reason: 'null_byte',\n });\n }\n\n const resolvedPath = path.resolve(filePath);\n\n // Default to the current working directory when no allowed directory is specified. This\n // prevents path traversal attacks by ensuring files can only be accessed within the CWD\n // or a more restrictive allowed directory.\n //\n // null and '' deliberately fall back to the CWD rather than meaning \"no restriction\":\n // callers routinely produce them from optional config or a JSON round trip, and silently\n // dropping the sandbox in that case would be a security hole. A caller that genuinely wants\n // an entire volume passes its root ('/' or 'C:\\\\'), which the containment test supports.\n const baseDir = allowedDir || process.cwd();\n const resolvedBaseDir = path.resolve(baseDir);\n\n const onDisk = isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath);\n const contained = onDisk === null ? isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) : onDisk.contained;\n\n if (!contained) {\n throw new QvdSecurityError('Path traversal detected: Access denied', {\n path: filePath,\n resolvedPath,\n allowedDir: resolvedBaseDir,\n reason: 'outside_allowed_directory',\n // Says which check refused, so a rejection of a path that looks contained is traceable to\n // a symlink or a case difference rather than looking like a bug.\n check: onDisk === null ? 'lexical' : 'filesystem',\n });\n }\n\n if (onDisk === null) {\n return {path: resolvedPath, base: resolvedBaseDir, target: resolvedPath, stats: null, onDisk: false};\n }\n\n return {path: resolvedPath, base: resolvedBaseDir, target: onDisk.target, stats: onDisk.stats, onDisk: true};\n}\n\n/**\n * Validates that a file path stays inside the allowed directory.\n *\n * `checkPath` without the half that says what the path reaches, for a caller that only needs the\n * answer. The reader and the writer do not use it: see `checkPath` for why.\n *\n * @param {string} filePath The path to validate.\n * @param {string|null} [allowedDir] Optional allowed directory path. Defaults to the current\n * working directory to prevent path traversal attacks.\n * @throws {QvdValidationError} If filePath is not a non-empty string, or allowedDir is not a\n * string, null or undefined.\n * @throws {QvdSecurityError} If path traversal is detected.\n * @return {string} The resolved absolute path. This is the lexically resolved path, not the\n * canonical one, so callers see the path they asked for.\n */\nexport function validatePath(filePath, allowedDir) {\n return checkPath(filePath, allowedDir).path;\n}\n","// @ts-check\n\nimport {QvdIOError} from '../QvdErrors.js';\n\n/**\n * Whether an error is the operating system's refusal of a file-system call.\n *\n * Node reports those as system errors, which name the call in `syscall` and the reason in `code`:\n * `ENOENT`, `EISDIR`, `EACCES`, `EBUSY`. Nothing else carries a `syscall` - not this library's own\n * errors, and not a `TypeError` from a bug. Nor did the `RangeError` a file handle's `readFile` raised\n * for a file above 2 GiB, a limit of Node's rather than a failure of the disk; a read no longer calls\n * it (#122).\n *\n * Tested by shape rather than with `instanceof Error`, because a system error is made in Node's own\n * realm, and a runner that sandboxes modules - Jest does - has a different `Error` to compare it with.\n *\n * @param {unknown} error What was thrown.\n * @return {boolean} True for a system error.\n */\nfunction isSystemError(error) {\n const candidate = /** @type {{code?: unknown, syscall?: unknown}|null} */ (error);\n\n return (\n candidate !== null &&\n typeof candidate === 'object' &&\n typeof candidate.syscall === 'string' &&\n typeof candidate.code === 'string'\n );\n}\n\n/**\n * A failed file-system call as a `QvdIOError`, or anything else unchanged.\n *\n * Every one of these used to reach the caller as Node's own error (#126), so a caller's\n * `catch (error) { if (error instanceof QvdError) ... }` saw a corrupt file but not a missing one.\n * The system code moves to `context.code` rather than being lost, and Node's error is kept whole as\n * `cause`.\n *\n * The message ends with Node's own - `ENOENT: no such file or directory, open '/data/sales.qvd'` -\n * so a log that prints only messages still names the code, and a search for it still finds the line.\n *\n * @param {unknown} error What the call threw.\n * @param {string} file The QVD file being read or written.\n * @param {'read'|'write'} direction Which of the two, for the message.\n * @return {unknown} A `QvdIOError` whose `cause` is `error`, if the operating system raised it;\n * otherwise `error` itself.\n */\nexport function asIoError(error, file, direction) {\n if (!isSystemError(error)) {\n return error;\n }\n\n const {message, syscall, code} = /** @type {{message: string, syscall: string, code: string}} */ (error);\n\n return new QvdIOError(\n `Could not ${direction} the QVD file: ${message}`,\n {file, operation: syscall, code},\n {cause: error},\n );\n}\n\n/**\n * A `.catch()` handler that rethrows a failed file-system call as a `QvdIOError`.\n *\n * Attached to each call rather than wrapped around the method that makes them, because those methods\n * also run code that is not a file-system call: a caller's `onProgress`, and `signal.throwIfAborted()`,\n * which throws whatever reason the caller aborted with. A system error thrown from either belongs to\n * the caller, and reporting it as a failure to read the QVD file would send them to the wrong place.\n *\n * @param {string} file The QVD file being read or written.\n * @param {'read'|'write'} direction Which of the two, for the message.\n * @return {(error: unknown) => never} The handler.\n */\nexport function rethrowAsIoError(file, direction) {\n return (error) => {\n throw asIoError(error, file, direction);\n };\n}\n\n/**\n * Runs `use` on an open file, then closes it - reporting a failed close only when `use` succeeded.\n *\n * `finally { await handle.close() }`, which this replaced, lets a close that fails replace the error\n * `use` was already throwing, and that error is the one that says what went wrong: a truncated file\n * read as a `QvdCorruptedError`, or a write the disk refused with `ENOSPC`, came back as an `EIO`\n * from the close. A close can fail on the same path for the same reason - a network share reports a\n * write's deferred error when the file is closed - so this is not only a corner case. The file is\n * still closed on that path; only the close's own failure is dropped. A read is one handle through\n * this, header and all, so the rule holds for every read as well as every write.\n *\n * When `use` succeeded, a failed close is the only news and is reported: after a write it can mean\n * the data never reached the disk.\n *\n * @template T\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {(error: unknown) => never} failed What a failed close is rethrown through - the\n * `rethrowAsIoError` handler of the read or write it belongs to.\n * @param {() => Promise<T>} use The work to do with the file.\n * @return {Promise<T>} What `use` returned.\n */\nexport async function closeAfter(handle, failed, use) {\n let result;\n\n try {\n result = await use();\n } catch (error) {\n await handle.close().catch(() => {});\n throw error;\n }\n\n await handle.close().catch(failed);\n\n return result;\n}\n","// @ts-check\n\nimport fs from 'fs';\n// Node's assert, for an invariant a bug in this library would violate - as the reader and the writer\n// use it - never for input.\nimport assert from 'assert';\nimport {QvdSecurityError} from '../QvdErrors.js';\n\n/**\n * `O_NOFOLLOW` where the platform defines it, and nothing where it does not.\n *\n * It makes an open() of a symlink fail with ELOOP instead of following it. POSIX defines it; Windows\n * does not, and `fs.constants.O_NOFOLLOW` is undefined there, so there the open follows a link and\n * it is the identity check that refuses what it reaches.\n */\nexport const NOFOLLOW = fs.constants.O_NOFOLLOW ?? 0;\n\nconst {O_RDONLY, O_WRONLY} = fs.constants;\n\n/**\n * What an open answers when the name it was given has become a symlink since it was checked. ELOOP\n * on Linux and macOS; EMLINK is how the BSDs answer the same thing.\n */\nconst BECAME_A_LINK = new Set(['ELOOP', 'EMLINK']);\n\n/**\n * How the file at a checked path differs from what the check approved.\n *\n * @typedef {'became_a_symlink'|'replaced'|'appeared'} Change\n */\n\n/** What each change says in a message. @type {Record<Change, string>} */\nconst DESCRIPTIONS = {\n became_a_symlink: 'the file became a symbolic link after it was checked',\n replaced: 'the file was replaced by a different one after it was checked',\n appeared: 'a file appeared at the path after it was checked',\n};\n\n/**\n * The error for a file that is not the file the containment check approved.\n *\n * A `QvdSecurityError` like any other containment refusal, with a reason of its own, because what\n * it reports is the same thing a refused path is: an open that would have reached a file the\n * sandbox did not approve. `change` says how, for a caller that logs it.\n *\n * @param {import('./validatePath.js').CheckedPath} checked What was checked.\n * @param {Change} change How the file differs from it.\n * @return {QvdSecurityError} The error.\n */\nfunction changedAfterCheck(checked, change) {\n return new QvdSecurityError(`Path traversal detected: ${DESCRIPTIONS[change]}`, {\n path: checked.path,\n resolvedPath: checked.target,\n allowedDir: checked.base,\n reason: 'changed_after_check',\n change,\n });\n}\n\n/**\n * Opens the file a checked path reaches, and holds the open to what the check approved.\n *\n * `checkPath` decides containment on a path, and a path can change between that decision and the\n * open that follows it - #247, a symlink swapped in after the check and followed by the open. So the\n * open is made on the file the check resolved rather than on the path, and two things hold it\n * there:\n *\n * - **`O_NOFOLLOW`.** The check resolved the file to its canonical path, whose last component was\n * not a symlink. One that is now is refused rather than followed.\n * - **Identity.** A file that existed at the check is compared with the descriptor by device and\n * inode, so a file replaced by another - or, where there is no `O_NOFOLLOW`, a symlink followed to\n * another - is refused. The comparison is of the descriptor, not of a second stat of the path:\n * a second stat would be a second resolution, and could be answered by a different file. And a read\n * of a name the check found empty that opens anyway is refused too: there is no identity to compare\n * it with, and what appeared could be a link to anywhere - which, without `O_NOFOLLOW`, the open\n * has already followed. The read would have failed with ENOENT a moment earlier.\n *\n * A rewrite is truncated here and only here, once the descriptor is known to be the right file.\n * `'w'` truncates as it opens, which would empty whatever the open reached before anything could\n * check that it was the file approved.\n *\n * A rewrite is only ever of a file that existed at the check, because only then is there an identity\n * to hold the open to. A write to a name nothing is at yet never comes here: the writer builds the\n * file beside the name and renames it there, in either mode, because a rename replaces a name rather\n * than following a link at it. An open that creates cannot promise that - on Windows even `O_EXCL`\n * follows a dangling symlink planted at the name, and creates the file wherever it points.\n *\n * What this does not cover, and nothing reached through Node's API can: a *directory* further up the\n * path swapped for a symlink after the check. The open resolves every directory it passes through,\n * and closing that needs `openat()` one component at a time with `O_NOFOLLOW`, which Node does not\n * expose. Nor, without `O_NOFOLLOW`, can Windows refuse a swapped-in link before the open has\n * followed it: the identity check refuses what it reached, but only after the open.\n *\n * Without an on-disk answer from the check - allowedDir did not exist, or the path would not resolve\n * - there is nothing to hold the open to, and it is made as it always was.\n *\n * @param {import('./validatePath.js').CheckedPath} checked What `checkPath` approved.\n * @param {'read'|'rewrite'} purpose Whether the file is read, or rewritten in place.\n * @param {(error: unknown) => never} failed The read's or write's `rethrowAsIoError` handler, for\n * everything that is the operating system's refusal rather than a change.\n * @param {{nofollow?: number}} [platform] `nofollow` is `NOFOLLOW` unless a test supplies another.\n * @return {Promise<import('fs/promises').FileHandle>} The open file. The caller closes it.\n * @throws {QvdSecurityError} If the file is not the one the check approved.\n */\nexport async function openChecked(checked, purpose, failed, {nofollow = NOFOLLOW} = {}) {\n assert(purpose === 'read' || checked.stats !== null, 'A rewrite in place is of a file that exists.');\n\n const noFollow = checked.onDisk ? nofollow : 0;\n const flags = (purpose === 'rewrite' ? O_WRONLY : O_RDONLY) | noFollow;\n\n /** @type {import('fs/promises').FileHandle} */\n let handle;\n\n try {\n handle = await fs.promises.open(checked.target, flags);\n } catch (error) {\n const {code} = /** @type {{code?: string}} */ (error) ?? {};\n\n if (checked.onDisk && noFollow !== 0 && code !== undefined && BECAME_A_LINK.has(code)) {\n throw changedAfterCheck(checked, 'became_a_symlink');\n }\n\n return failed(error);\n }\n\n const stats = checked.stats;\n\n if (stats === null) {\n if (checked.onDisk) {\n await handle.close().catch(() => {});\n throw changedAfterCheck(checked, 'appeared');\n }\n\n return handle;\n }\n\n try {\n const opened = await handle.stat({bigint: true}).catch(failed);\n\n if (opened.dev !== stats.dev || opened.ino !== stats.ino) {\n throw changedAfterCheck(checked, 'replaced');\n }\n\n // Only a regular file: O_TRUNC does nothing to a device or a FIFO, and ftruncate refuses one.\n if (purpose === 'rewrite' && stats.isFile()) {\n await handle.truncate(0).catch(failed);\n }\n } catch (error) {\n // The error on its way out says what went wrong; a close that fails as well is not news.\n await handle.close().catch(() => {});\n throw error;\n }\n\n return handle;\n}\n","// @ts-check\n\nimport crypto from 'crypto';\nimport fs from 'fs';\nimport path from 'path';\nimport {setTimeout as wait} from 'timers/promises';\n\n/**\n * The longest file name the usual filesystems accept, in bytes - ext4, APFS, HFS+, XFS, NTFS and SMB\n * all stop at 255. Bytes rather than characters: the limit is on the encoded name, so a name of\n * accented or CJK characters reaches it sooner than its length suggests.\n */\nconst MAX_NAME_BYTES = 255;\n\n/**\n * Keeps at most `budget` bytes of a name, cutting whole characters.\n *\n * `Buffer.prototype.subarray` would cut in the middle of a multi-byte character and leave a\n * replacement character in the name, so the characters are counted instead - `for...of` walks code\n * points, which keeps a surrogate pair together as well.\n *\n * @param {string} name The name to shorten.\n * @param {number} budget How many bytes of it may be kept.\n * @return {string} As much of the start of it as fits.\n */\nfunction firstBytesOf(name, budget) {\n if (Buffer.byteLength(name) <= budget) {\n return name;\n }\n\n let kept = '';\n let bytes = 0;\n\n for (const character of name) {\n const size = Buffer.byteLength(character);\n\n if (bytes + size > budget) {\n break;\n }\n\n kept += character;\n bytes += size;\n }\n\n return kept;\n}\n\n/**\n * The temporary file a write builds before it replaces the destination.\n *\n * It sits in the destination's own directory, because a rename is only atomic within one filesystem\n * and a temporary directory can be on another. Three things about the name are deliberate:\n *\n * - **It does not end in `.qvd`.** A Qlik load that names a folder rather than a file -\n * `LOAD * FROM [lib://data/*.qvd] (qvd)` - would otherwise pick a half-written one up as a table.\n * - **It says what left it.** A process killed part-way through a write cannot remove its temporary\n * file, so one can survive beside the QVD, and whoever finds it should be able to tell what wrote\n * it and that it was never meant to last.\n * - **It is random, and opened with `'wx'`.** Two processes writing the same QVD never share one, and\n * a name planted in advance - a symlink out of the allowed directory, say - is not written through.\n *\n * The destination's own name is kept only as far as it fits. The marks above add 27 bytes, and a file\n * name may be 255, so a QVD named with 229 or more would otherwise have been given a temporary file\n * the filesystem refuses outright: `toQvd()` failed with ENAMETOOLONG on a name it had written\n * happily until 2.0.0 - measured at 235 characters, where the in-place write still succeeded. What is\n * cut is the end, so the part that identifies the file survives.\n *\n * @param {string} target The file to be replaced.\n * @return {string} The temporary file to build it in.\n */\nexport function temporaryPathFor(target) {\n const marks = `.qvdjs-${crypto.randomBytes(8).toString('hex')}.tmp`;\n const name = `${firstBytesOf(path.basename(target), MAX_NAME_BYTES - marks.length)}${marks}`;\n\n return path.join(path.dirname(target), name);\n}\n\n/**\n * What Windows answers while something else has the file open. POSIX has no equivalent: there EPERM\n * and EACCES are about the directory's permissions, which waiting does not change.\n */\nconst IN_USE = new Set(['EPERM', 'EACCES', 'EBUSY']);\n\n/**\n * How long to wait before each further attempt, in milliseconds - seven attempts within two thirds of\n * a second. Long enough for a scanner to let go of a file it opened when this write closed it, and\n * short enough that a file genuinely held open still fails while the caller is watching.\n */\nconst RETRY_DELAYS = [10, 20, 40, 80, 160, 320];\n\n/**\n * Runs a file-system call, retrying on Windows while it answers that the file is in use.\n *\n * Two kinds of program hold a QVD open briefly without anyone asking them to: a virus scanner or an\n * indexer opening the file this write has just closed, and Qlik Sense reading the one it is about to\n * replace. Neither keeps it for long. graceful-fs, which npm installs through, retries a rename on\n * Windows for these same codes and for this same reason.\n *\n * The error of the last attempt is the one thrown, so a file that is genuinely held open is still\n * reported as `EPERM` rather than as something about retrying.\n *\n * @template T\n * @param {() => Promise<T>} call The call to make.\n * @param {{platform?: string, delays?: Array<number>}} [options] `platform` and `delays` are taken\n * from the running process unless a test supplies them.\n * @return {Promise<T>} What the call returned.\n */\nasync function retrying(call, {platform = process.platform, delays = RETRY_DELAYS} = {}) {\n for (let attempt = 0; ; attempt++) {\n try {\n return await call();\n } catch (error) {\n const {code} = /** @type {{code?: string}} */ (error) ?? {};\n\n if (platform !== 'win32' || attempt >= delays.length || code === undefined || !IN_USE.has(code)) {\n throw error;\n }\n\n await wait(delays[attempt]);\n }\n }\n}\n\n/**\n * Renames `from` over `to`, retrying while Windows reports either as in use.\n *\n * This is the step that makes a write atomic. On POSIX, and on one NTFS volume, it either replaces the\n * destination with the finished file or leaves it exactly as it was; nothing that reads the path sees\n * a part of one.\n *\n * @param {string} from The finished temporary file.\n * @param {string} to The destination it replaces.\n * @param {{platform?: string, delays?: Array<number>}} [options] As `retrying` takes them.\n * @return {Promise<void>} Resolves once the destination is the new file.\n */\nexport function renameOver(from, to, options) {\n return retrying(() => fs.promises.rename(from, to), options);\n}\n\n/**\n * Removes a temporary file that will not be used, throwing nothing.\n *\n * Every call reaches this from a failure that is already on its way to the caller, and that failure\n * says what went wrong. A temporary file that cannot be removed as well is the lesser news, and\n * throwing here would replace the error that explains the write with one about the tidying up. It is\n * still news, though, so it is reported by the answer rather than by an error: the writer names the\n * file it could not remove in the error it is already throwing.\n *\n * @param {string} file The temporary file.\n * @param {{platform?: string, delays?: Array<number>}} [options] As `retrying` takes them.\n * @return {Promise<boolean>} Whether it is gone.\n */\nexport async function removeTemporary(file, options) {\n try {\n // `rm` with `force` rather than `unlink`, for its one useful difference: a file that is already\n // gone is not an error. Something else can remove a temporary file - a system that sweeps them,\n // or a scanner that quarantines one - and reporting that as a failure to remove it would have the\n // writer name a file the caller cannot find in the error it throws.\n //\n // Its own `maxRetries` is left alone. Retrying is this module's to decide, because the rename\n // faces the same Windows condition and the two have to answer it the same way; `rm` retries a\n // different set of codes, on every platform, for a budget of its own.\n await retrying(() => fs.promises.rm(file, {force: true}), options);\n\n return true;\n } catch {\n return false;\n }\n}\n","// @ts-check\n\nimport {QvdCorruptedError} from '../QvdErrors.js';\n\n/**\n * Largest `BitWidth` a field may declare.\n *\n * A stored index is an offset into the field's symbol table, and it is kept in an `Int32Array`,\n * so it has to fit in a positive 32-bit integer. 31 bits addresses 2,147,483,647 symbols in a\n * single field - orders of magnitude beyond anything the rest of the library will load, since\n * the symbol table for that many values would be terabytes and the memory guard refuses long\n * before. A file declaring more is refused rather than decoded: at 32 bits the top of the range\n * wraps to a negative index, which read back as NULL before #125 - silently wrong values instead of\n * an error, the shape bug #113 was. `decodeIndexColumn` now refuses such an index as well, but the\n * header is where the damage is, so that is where it is named.\n */\nexport const MAX_BIT_WIDTH = 31;\n\n/**\n * Powers of two up to 2^39, the widest window a field can span: at most 7 bits of byte\n * misalignment plus `MAX_BIT_WIDTH`. Every value here is exactly representable as a double, and\n * so is every intermediate the decoder forms, which is why the arithmetic below can use `/` and\n * `%` on Numbers rather than 32-bit bitwise operators - those would overflow at 32 bits.\n */\nconst POW2 = Array.from({length: 41}, (_, exponent) => 2 ** exponent);\n\n/**\n * Where a field's bits sit inside a record.\n *\n * Both directions need this, and they must not derive it separately. Two copies of\n * `(shift + bitWidth + 7) >> 3` that drift apart write files this library cannot read, and\n * nothing throws - the decode simply starts a byte early and every field after the first\n * straddling one is misaligned. That is #113's failure shape pointed the other way, so the\n * derivation lives here and the encoder, the decoder and their tests all call it.\n *\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits; zero means it occupies no bits at all.\n * @return {{byteStart: number, shift: number, byteCount: number}} The field's byte window:\n * where it starts, how far into that byte it begins, and how many bytes it touches (0 when\n * the width is zero, otherwise 1 to 5).\n */\nexport function fieldGeometry(bitOffset, bitWidth) {\n const shift = bitOffset & 7;\n\n return {\n byteStart: bitOffset >>> 3,\n shift,\n byteCount: bitWidth === 0 ? 0 : (shift + bitWidth + 7) >>> 3,\n };\n}\n\n/**\n * Decodes one bit-packed field out of every record of an index table.\n *\n * ## The layout\n *\n * A record is `recordSize` bytes. Numbering its bits `p = 0, 1, 2, ...`, bit `p` is\n * `(byte[p >> 3] >> (p & 7)) & 1` - little-endian, least significant bit of each byte first. A\n * field occupies `bitWidth` consecutive bits starting at `bitOffset`, least significant bit\n * first, and `Bias` is then added to the value read.\n *\n * This is the same layout the previous implementation produced, by a much longer route: it\n * reversed the record's bytes, concatenated their binary spellings into a string of\n * `recordSize * 8` characters, split that into an array of one number per bit, reversed it, then\n * sliced the array per field and summed `bit * Math.pow(2, index)`. Several arrays the length of\n * the record in *bits*, built and discarded for every row, which is where roughly 98% of a full\n * read went.\n *\n * ## Why the arithmetic is not bitwise\n *\n * JavaScript's `<<`, `>>>` and `&` coerce to 32 bits, and a field can span up to 39 bits once\n * byte misalignment is counted. `Math.floor(acc / 2**shift) % 2**bitWidth` is exact for every\n * value this can form, because the widest accumulator is under 2^40 and doubles are exact to\n * 2^53.\n *\n * ## Which indices address something\n *\n * With `bounds`, each index is checked as it is decoded, and the first one that addresses nothing\n * is refused. An index addresses a symbol when it is at least 0 and below the field's symbol count.\n * It is the field's NULL when it equals a negative `bias`, which is stored index 0 under Qlik's -2.\n * Anything else points past the end of the symbols or below their start. Neither Qlik nor this\n * library writes such an index, so it is damage. Unchecked, one past the end read back as\n * `undefined` and one below the start as NULL, and neither threw (#125).\n *\n * The check runs on the exact value, before the `Int32Array` stores it. On the taxi fixture's 34\n * million indices it costs about 9 ms against 368 ms for the decode, where a separate pass over the\n * decoded column cost 32 ms. `validateFieldBitMetadata` has already refused a bias whose indices do\n * not fit in 32 bits, so the store cannot turn a refused index into an accepted one, or the other\n * way round.\n *\n * @param {Buffer|Uint8Array} buffer The index table, starting at the first record.\n * @param {number} recordSize Bytes per record.\n * @param {number} rowCount Number of records to decode.\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits. Zero means the field holds a single\n * distinct value and occupies no bits at all.\n * @param {number} bias Added to every decoded value. Qlik writes -2 for a field containing\n * NULLs, where stored index 0 means NULL and real symbols start at 2.\n * @param {Int32Array} out Destination, at least `rowCount` long.\n * @param {IndexBounds|null} [bounds=null] What an index has to address, and what to name when one\n * does not. Null decodes without checking. The symbol-usage pass does that, because it runs before\n * the symbols are parsed, and the decode that follows checks the same rows.\n * @return {Int32Array} `out`.\n * @throws {QvdCorruptedError} With `bounds`, if an index addresses neither a symbol nor NULL.\n */\nexport function decodeIndexColumn(buffer, recordSize, rowCount, bitOffset, bitWidth, bias, out, bounds = null) {\n // Every index at or above this addresses nothing. Infinity when unchecked, so the one test in the\n // loop below never fires.\n const symbolCount = bounds === null ? Infinity : bounds.symbolCount;\n\n // A single-distinct-value column occupies zero bits, so there is nothing to read: every row\n // holds stored index 0, which is `bias` once the bias is applied. That is a symbol, the NULL\n // marker, or - past the end of the symbols - wrong in every row, so the first is refused.\n if (bitWidth === 0) {\n if (bounds !== null && rowCount > 0 && bias >= symbolCount) {\n refuse(bounds, 0, bias, bias);\n }\n\n out.fill(bias, 0, rowCount);\n return out;\n }\n\n const {byteStart, shift, byteCount} = fieldGeometry(bitOffset, bitWidth);\n\n const divisor = POW2[shift];\n const modulus = POW2[bitWidth];\n\n // byteStart + byteCount is at most recordSize - validateFieldBitMetadata has already required\n // bitOffset + bitWidth <= recordSize * 8 - so every read below is inside the record, and the\n // caller has established that `rowCount` whole records are present.\n let base = byteStart;\n\n for (let row = 0; row < rowCount; row++, base += recordSize) {\n let acc = buffer[base];\n\n if (byteCount > 1) acc += buffer[base + 1] * 0x100;\n if (byteCount > 2) acc += buffer[base + 2] * 0x10000;\n if (byteCount > 3) acc += buffer[base + 3] * 0x1000000;\n if (byteCount > 4) acc += buffer[base + 4] * 0x100000000;\n\n const index = (Math.floor(acc / divisor) % modulus) + bias;\n\n // Past the end of the symbols, or below zero without being the NULL marker. `bounds` is tested\n // last, so a valid index costs the two comparisons it fails and nothing more.\n if ((index >= symbolCount || (index < 0 && index !== bias)) && bounds !== null) {\n refuse(bounds, row, index, bias);\n }\n\n out[row] = index;\n }\n\n return out;\n}\n\n/**\n * What a decoded index has to address, and what to name in the error when one does not.\n *\n * @typedef {Object} IndexBounds\n * @property {number} symbolCount The field's symbols. A valid index is below this.\n * @property {string} field The field name.\n * @property {string} file The file.\n * @property {number} firstRow The file row the decode starts at, so the error names the row in the\n * file rather than in a window or a chunk.\n */\n\n/**\n * Refuses an index that addresses neither a symbol nor NULL.\n *\n * @param {IndexBounds} bounds What the index had to address.\n * @param {number} row The row, counted from the start of this decode.\n * @param {number} index The index, bias applied.\n * @param {number} bias The field's bias.\n * @return {never}\n * @throws {QvdCorruptedError} Always.\n */\nfunction refuse(bounds, row, index, bias) {\n throw new QvdCorruptedError('Symbol index out of range', {\n field: bounds.field,\n row: bounds.firstRow + row,\n symbolIndex: index,\n symbolCount: bounds.symbolCount,\n bias,\n file: bounds.file,\n stage: 'parseIndexTable',\n });\n}\n\n/**\n * Writes one bit-packed field into one record. The inverse of `decodeIndexColumn`.\n *\n * Same layout, written the other way: bit `p` of a record is `(byte[p >> 3] >> (p & 7)) & 1`,\n * so a value is shifted left by the field's `shift` and OR-ed across the bytes it touches. The\n * buffer must start zeroed and fields must not overlap, which the caller guarantees by\n * allocating it with `Buffer.alloc` and laying columns out by prefix sum of their widths.\n *\n * Multiplication rather than `<<` for the same reason the decoder divides rather than `>>>`: a\n * field can span 39 bits once misalignment is counted, and JavaScript's bitwise operators stop\n * at 32. Every intermediate here is under 2^40, well inside what a double represents exactly.\n *\n * It takes the geometry rather than a `bitOffset`, so the caller cannot derive the byte window\n * differently from the way `decodeIndexColumn` derives it - see `fieldGeometry`. A zero-width\n * field writes nothing, matching the decoder's zero-width branch, which reads nothing; the\n * first byte used to be written unconditionally, so a `byteCount` of 0 put the value into the\n * next column's bits.\n *\n * @param {Buffer|Uint8Array} buffer The index table being built.\n * @param {number} recordBase Index of the record's first byte.\n * @param {{byteStart: number, shift: number, byteCount: number}} geometry From `fieldGeometry`.\n * @param {number} value The stored index. Must fit in the field's width; the caller checks.\n */\nexport function writeBitField(buffer, recordBase, geometry, value) {\n const {byteStart, shift, byteCount} = geometry;\n\n if (byteCount === 0) {\n return;\n }\n\n const base = recordBase + byteStart;\n const shifted = value * POW2[shift];\n\n buffer[base] |= shifted % 0x100;\n\n if (byteCount > 1) buffer[base + 1] |= Math.floor(shifted / 0x100) % 0x100;\n if (byteCount > 2) buffer[base + 2] |= Math.floor(shifted / 0x10000) % 0x100;\n if (byteCount > 3) buffer[base + 3] |= Math.floor(shifted / 0x1000000) % 0x100;\n if (byteCount > 4) buffer[base + 4] |= Math.floor(shifted / 0x100000000) % 0x100;\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\nimport xml from 'xml2js';\n// Node's assert, used only for invariants a bug in this library would violate - \"this private\n// method ran after the one that fills the field it reads\". Never for input: everything a caller\n// can get wrong throws a QvdError with a context object instead.\n//\n// #143 read the old Copilot instruction \"use assertions for validation\" as an explanation for\n// these calls. It is not: every one sits after a method that either assigns the field\n// unconditionally or throws, and 3,570 corruption cases across every bundled fixture and every\n// entry point produced no AssertionError. They are checked, and they stay.\nimport assert from 'assert';\nimport {QvdIOError, QvdValidationError} from './QvdErrors.js';\nimport {checkPath} from './util/validatePath.js';\nimport {closeAfter, rethrowAsIoError} from './util/ioErrors.js';\nimport {openChecked} from './util/openChecked.js';\nimport {removeTemporary, renameOver, temporaryPathFor} from './util/replaceFile.js';\nimport {booleanOption} from './util/optionTypes.js';\nimport {fieldGeometry, writeBitField} from './util/bitUtils.js';\nimport {\n asDual,\n checkNumber,\n checkText,\n constructorName,\n describeType,\n isNumericText,\n numberProblem,\n textProblem,\n} from './util/cellRules.js';\nimport {kindOf, symbolByteLength, writeSymbol} from './util/symbolBytes.js';\nimport {firstTextByValue, normaliseStoredSymbols, sameValueZero} from './util/storedSymbols.js';\n\n/**\n * @typedef {import('./QvdDataFrame.js').QvdDataFrame} QvdDataFrame\n */\n\n/**\n * Persists a QVD file to disk.\n */\n/**\n * The index of the first character in a text that XML 1.0 cannot hold, even written as a character\n * reference: a C0 control other than tab, line feed and carriage return, or U+FFFE or U+FFFF. NUL is one\n * of them; a surrogate without its pair, the other thing XML cannot hold, is `textProblem`'s to report.\n *\n * @param {string} value The text.\n * @return {number} The index, or -1 when there is none.\n */\nfunction notXmlIndex(value) {\n for (let index = 0; index < value.length; index++) {\n const unit = value.charCodeAt(index);\n\n if ((unit < 0x20 && unit !== 0x09 && unit !== 0x0a && unit !== 0x0d) || unit === 0xfffe || unit === 0xffff) {\n return index;\n }\n }\n\n return -1;\n}\n\n/**\n * Throws unless a text can be written into the XML header.\n *\n * The header is XML, which has no way to write a NUL, a surrogate without its pair or a control\n * character such as U+0001. The builder refused each with a bare `Error: Invalid character in string`,\n * naming neither the field nor the property. A read can produce such a text: the parser accepts a raw\n * control character in the header it reads, so a file carrying one in its table name read without\n * complaint and could not be written back.\n *\n * @param {string} value The text.\n * @param {string} subject What the text is, capitalised, as the message starts.\n * @param {Object} context Where the text came from, merged into the error's context.\n * @throws {QvdValidationError} If the text holds a character the header cannot; `context.position` is\n * its index.\n */\nfunction checkHeaderText(value, subject, context) {\n checkText(value, subject, context);\n\n const position = notXmlIndex(value);\n\n if (position !== -1) {\n const code = value.charCodeAt(position).toString(16).toUpperCase().padStart(4, '0');\n\n throw new QvdValidationError(`${subject} cannot contain U+${code}, which XML cannot hold`, {...context, position});\n }\n}\n\n/**\n * Checks every text in a part of the header: a string, or the strings inside an object or an array, as\n * the XML builder would write them.\n *\n * @param {any} value The value.\n * @param {string} property Its path in the header, such as `Lineage.LineageInfo.Statement`.\n * @param {string} owner What the property belongs to, for the message: `the table`, or a field.\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If a text holds a character the header cannot.\n */\nfunction checkHeaderTexts(value, property, owner, context) {\n if (typeof value === 'string') {\n checkHeaderText(value, `The ${property} of ${owner}`, {...context, property});\n } else if (Array.isArray(value)) {\n value.forEach((item, index) => checkHeaderTexts(item, `${property}[${index}]`, owner, context));\n } else if (value !== null && typeof value === 'object') {\n for (const [key, item] of Object.entries(value)) {\n checkHeaderTexts(item, `${property}.${key}`, owner, context);\n }\n }\n}\n\n/**\n * Checks the field names before a single row is walked.\n *\n * All three of these produced a file rather than an error. A non-string name was written as\n * whatever it stringified to; a duplicate produced two fields of one name, which makes\n * `at(row, name)` and `select(name)` answer about the first and ignore the second - and which\n * broke two-pass symbol filtering, because the usage sets were keyed by name (#181); and an empty\n * name produced a field nothing can address. A name the header cannot hold - see `checkHeaderText` -\n * is refused here too, before the rows rather than after them.\n *\n * @param {Array<any>} columns The field names.\n * @param {string} filePath The file being written, for the error.\n * @throws {QvdValidationError} If a name is not a usable, unique string.\n */\nfunction validateColumnNames(columns, filePath) {\n /** @type {Set<string>} */\n const seen = new Set();\n\n columns.forEach((name, index) => {\n if (typeof name !== 'string' || name.length === 0) {\n throw new QvdValidationError('Field names must be non-empty strings', {\n column: index,\n provided: name,\n type: typeof name,\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n checkHeaderText(name, 'A field name', {column: index, provided: name, file: filePath, stage: 'buildSymbolTable'});\n\n if (seen.has(name)) {\n throw new QvdValidationError(`Field '${name}' appears twice`, {\n column: name,\n columnIndex: index,\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n seen.add(name);\n });\n}\n\n/**\n * Refuses a cell that is neither a number, a string, a dual value nor NULL.\n *\n * Everything refused here previously produced either a raw `TypeError` from deep inside\n * `Buffer.from`, naming neither the field nor the row, or a file. The file cases are the reason\n * this is not merely a nicer error message: `[1, 2]` became `Buffer.from([1, 2])`, so the array was\n * written as the two *bytes* 1 and 2 and read back as two control characters; and a `Date` was\n * written as its full `toString()`, which carries the writing machine's timezone and locale into the\n * data.\n *\n * A `QvdSymbol` is refused too. It carries a storage kind, which the writer derives from the value\n * instead, and a dual symbol built through its factories was never a dual cell anyone could read back.\n * So is an object that only resembles a dual - `{number, text, date}`, or one that inherits the two\n * properties - because storing it as one would discard the rest of it without a word.\n *\n * Numbers and strings are checked in `cellRules`, which is where the other things that used to\n * produce a file are refused: a string containing a NUL, which ends a string symbol early and made\n * `toQvd` produce a file this same library refuses to read; a string containing an unpaired\n * surrogate, which UTF-8 cannot encode, so it was written as U+FFFD and two different strings could\n * become one stored value; and `NaN` or an infinity, which came back as the string `'NaN'` or as the\n * infinity itself.\n *\n * @param {any} value The value.\n * @param {string} column The field it belongs to, for the error.\n * @param {number} row The row it was first seen on, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {never}\n * @throws {QvdValidationError} Always.\n */\nfunction refuseCell(value, column, row, filePath) {\n let resemblesDual = false;\n\n try {\n resemblesDual =\n value !== null &&\n typeof value === 'object' &&\n ('number' in value || 'text' in value || ('intValue' in value && 'stringValue' in value));\n } catch {\n // A revoked Proxy throws from `in`. It resembles nothing.\n }\n\n throw new QvdValidationError(\n `A QVD field holds numbers, strings, dual values and NULL; ${describeType(value)} cannot be written. ` +\n `Convert it first - a Date to new QvdDual(dateToQlikSerial(date), text), the serial and the text Qlik shows, ` +\n `which is how Qlik stores a date; a boolean to -1 and 0, as a Qlik comparison stores it.` +\n (resemblesDual ? ' A dual value is a QvdDual, or an object whose only keys are number and text.' : ''),\n {\n column,\n row,\n type: typeof value,\n constructor: constructorName(value) ?? undefined,\n file: filePath,\n stage: 'buildSymbolTable',\n },\n );\n}\n\n/**\n * How many dual objects a column remembers by identity before it stops adding them: this many, plus\n * two for every symbol the column holds.\n *\n * A read shares one `QvdDual` per symbol between every row that holds it, so remembering each object\n * makes a repeat cost one lookup, as a repeated number does. A caller who builds a fresh object per\n * row would add one entry per row instead - two million rows, two million entries - so past the bound\n * an object is resolved by its number on every row, which costs a validation and a lookup and holds\n * nothing.\n */\nconst OBJECT_MEMO_BASE = 64;\n\n/**\n * One column's symbols while they are collected.\n *\n * `keys` and `texts` are the slots, in first-appearance order: a slot's key is its number or its\n * string, and its text is the text of a dual, or null. `byKey` maps a key to its slot, so one number is\n * one symbol however it arrived - a plain number, a dual object, a cell resolved through the record.\n * `byCell` maps a primitive cell to its slot, and is `byKey` itself unless the field has a record\n * entry that can map a cell to a different key. `byObject` remembers dual objects by identity, up to\n * a bound.\n *\n * A record entry is looked up one of two ways. When every value in it is its own number - as in every\n * entry a `{duals: 'number'}` read builds without `coerceNumericStrings` - a cell is still its own key,\n * and the entry only gives it a text: `textByNumber`. Any other entry can make a cell stand for another\n * key, or for more than one, and `byValue` lists every symbol holding each value, so all of them can be\n * weighed.\n *\n * @typedef {Object} ColumnSymbols\n * @property {string} name The field name.\n * @property {Array<number|string>} keys Each slot's number or string.\n * @property {Array<string|null>} texts Each slot's text, or null.\n * @property {Map<number|string, number>} byKey Key to slot.\n * @property {Map<number|string, number>} byCell Primitive cell to slot.\n * @property {Map<object, number>} byObject Dual object to slot, bounded.\n * @property {import('./util/storedSymbols.js').StoredSymbolsEntry|null} entry The field's record entry.\n * @property {Map<number|string, string>|null} textByNumber For an entry whose every value is its own\n * number, each number's first text.\n * @property {Map<number|string, number|Array<number>>|null} byValue For any other entry, each value's\n * index or indices in it.\n * @property {SlotFacts} facts What kinds of value the slots hold, for the header.\n */\n\n/**\n * What kinds of value a column's written symbols hold - what decides which of its tags and number\n * format still describe it.\n *\n * @typedef {Object} SlotFacts\n * @property {boolean} hasNumber Some symbol has a number: a pure number or a dual.\n * @property {boolean} hasNonNumber Some symbol is a pure string.\n * @property {boolean} hasFraction Some number is not a whole number.\n */\n\n/**\n * Whether every symbol in a record entry is keyed by the value its cell holds - the symbol's own number,\n * as it is for a dual read as its number and for a pure number recorded beside one.\n *\n * Such an entry cannot make a value ambiguous - each value stands for one number, and no symbol in it\n * is a string - and never maps a cell to a key other than itself. So the cell needs no map of its own\n * and no weighing of entries, only the text the first symbol holding it has.\n *\n * @param {import('./util/storedSymbols.js').StoredSymbolsEntry} entry The entry.\n * @return {boolean} True when every value is its symbol's number.\n */\nfunction valuesAreNumbers(entry) {\n const {values, numbers} = entry;\n\n // A pure string's number is null, which no value is the same as.\n for (let index = 0; index < values.length; index++) {\n if (!sameValueZero(values[index], numbers[index])) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * A slot added after the column's others, for a key it does not have. The caller puts the key in\n * `byKey`.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} key The number or string.\n * @param {string|null} text The text supplied with it, or null.\n * @return {number} The slot.\n */\nfunction newSlot(column, key, text) {\n const slot = column.keys.length;\n\n column.keys.push(key);\n column.texts.push(text);\n\n // Every slot is created here, so the facts cost nothing extra: no pass over the symbols afterwards.\n if (typeof key === 'number') {\n column.facts.hasNumber = true;\n if (!Number.isInteger(key)) column.facts.hasFraction = true;\n } else {\n column.facts.hasNonNumber = true;\n }\n\n return slot;\n}\n\n/**\n * The slot for a key, created at its first appearance.\n *\n * A text is attached to a number slot that has none, in place, whatever order the cells came in: a\n * plain number carries no text, so a dual with the same number supplies it rather than losing it. A\n * slot that already has a text keeps it, which is Qlik's rule - values sharing a number share the first\n * text encountered.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} key The number or string.\n * @param {string|null} text The text supplied with it, or null.\n * @return {number} The slot.\n */\nfunction slotFor(column, key, text) {\n let slot = column.byKey.get(key);\n\n if (slot === undefined) {\n slot = newSlot(column, key, text);\n column.byKey.set(key, slot);\n } else if (text !== null && column.texts[slot] === null && typeof key === 'number') {\n column.texts[slot] = text;\n }\n\n return slot;\n}\n\n/**\n * Whether some of a record entry's symbols say different things about the value they share: two\n * numbers, two texts of pure strings, or a number and a pure string. Those are the symbols one cell\n * could stand for, and the writer refuses to pick one.\n *\n * @param {ReadonlyArray<number>} indices Indices into the entry of symbols that read as one value.\n * @param {ReadonlyArray<number|null>} numbers The entry's numbers.\n * @param {ReadonlyArray<string|null>} texts The entry's texts.\n * @return {boolean} True when they stand for more than one stored value.\n */\nfunction standsForSeveral(indices, numbers, texts) {\n /** @type {number|null} */\n let number = null;\n /** @type {string|null} */\n let string = null;\n\n for (const index of indices) {\n if (numbers[index] !== null) {\n if (number === null) {\n number = numbers[index];\n } else if (!sameValueZero(number, numbers[index])) {\n return true;\n }\n } else if (string === null) {\n string = texts[index];\n } else if (string !== texts[index]) {\n return true;\n }\n }\n\n return number !== null && string !== null;\n}\n\n/**\n * Whether a field whose record entry this is could have been read with `{duals: 'text'}` and, read that\n * way without `coerceNumericStrings`, would still have a value that stands for more than one stored value.\n *\n * Without coercion such a read shows every symbol with a text as that text, and a pure number as itself,\n * so the entry's symbols are grouped that way and weighed as the writer weighs a cell. Every symbol that\n * could end up in such a group is in the entry already: a `'text'` read records every dual, and a string\n * with a dual's text is either numeric, so coercion read it as a number and recorded it, or not, so the\n * dual reads as that text with coercion too and the string is recorded beside it.\n *\n * A dual shown as its number whose text is not numeric proves the entry came from a `'number'` read,\n * because a `'text'` read shows that text. Without coercion a `'number'` read maps no value to two stored\n * values: every value it records is a number, and every symbol under one number has that number.\n *\n * @param {import('./util/storedSymbols.js').StoredSymbolsEntry} entry The entry.\n * @return {boolean} True when a `'text'` read without coercion could still be refused.\n */\nfunction ambiguousAsUncoercedText(entry) {\n const {values, numbers, texts} = entry;\n\n for (let index = 0; index < values.length; index++) {\n if (typeof values[index] === 'number' && numbers[index] !== null && texts[index] !== null) {\n // @ts-ignore - the text was just checked for null\n if (!isNumericText(texts[index])) {\n return false;\n }\n }\n }\n\n /** @type {Map<number|string|null, Array<number>>} */\n const byShown = new Map();\n\n for (let index = 0; index < values.length; index++) {\n const shown = texts[index] ?? numbers[index];\n const indices = byShown.get(shown);\n\n if (indices === undefined) {\n byShown.set(shown, [index]);\n } else {\n indices.push(index);\n }\n }\n\n for (const indices of byShown.values()) {\n if (indices.length > 1 && standsForSeveral(indices, numbers, texts)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether reading the field with `{duals: 'both'}`, coercion left as it was, would leave no value standing\n * for more than one stored value.\n *\n * `'both'` records no dual - each is a `QvdDual` cell of its own - so under a value such a read records the\n * entry's symbols less its duals: strings coercion read as that number, and pure symbols beside them. Every\n * one of those is in the entry already, whichever mode built it, because coercion and the pure symbols\n * beside what it records do not depend on the mode.\n *\n * @param {ColumnSymbols} column The column, whose entry has a value that stands for several stored values.\n * @return {boolean} True when `'both'` is enough.\n */\nfunction unambiguousWithoutDuals(column) {\n // @ts-ignore - only a column with a byValue map refuses a value, and it has an entry\n const {numbers, texts} = column.entry;\n\n // @ts-ignore - see above\n for (const found of column.byValue.values()) {\n if (typeof found !== 'number') {\n const kept = found.filter((/** @type {number} */ index) => numbers[index] === null || texts[index] === null);\n\n if (kept.length > 1 && standsForSeveral(kept, numbers, texts)) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * What to do about a field in which a value stands for more than one stored value - the end of that\n * refusal.\n *\n * It names the least change to the read after which no value of the field does, so it is worked out from\n * every value in the field's entry and not only the one refused: advice fitted to that one could lead to a\n * second refusal for another. The entry does not say which duals mode built it, only sometimes shows it: a\n * dual shown as its text comes from a `'text'` read, and one shown as its number whose text is not a\n * number from a `'number'` read. Where the least change depends on the mode, the sentence says how.\n *\n * - **No value stands for a string read as a number beside another stored value:** `{duals: 'both'}`, or\n * `QvdDual` cells. Coercion can stay on, because a string it reads as a number reads as that number in\n * every mode: had it made a value ambiguous, that value would be among the ones weighed.\n * - **One does, and dropping coercion is enough for any read:** without `coerceNumericStrings`. A string\n * then reads as itself, and under `'number'` and `'both'` nothing is left to record two stored values\n * under one value; see `ambiguousAsUncoercedText` for `'text'`.\n * - **Dropping coercion is not enough for a `'text'` read, and `{duals: 'both'}` is:** that, for any read.\n * A string `'4'` beside a dual 4 with the text `4` is the example: a `'text'` read without coercion shows\n * both as `'4'`, and `'both'` shows the dual as a `QvdDual`.\n * - **Neither is enough on its own for a `'text'` read:** both, when the entry shows a `'text'` read. When\n * it does not, the read may have been `'number'`, for which dropping coercion is enough, so the sentence\n * asks for `'both'` as well only if the field was read with `'text'`. Switching to `'number'` is not\n * enough either: it records every dual `'both'` leaves out, and what is ambiguous without them stays so.\n *\n * `'007'` and `'7'` read as 7 in every mode, so a refusal that named only `'both'` for them would send\n * the caller to a read that is refused again.\n *\n * @param {ColumnSymbols} column The column, whose entry has a value that stands for several stored values.\n * @return {string} The sentence.\n */\nfunction ambiguityRemedy(column) {\n // @ts-ignore - only a column with a byValue map refuses a value, and it has an entry\n const {values, numbers, texts} = column.entry;\n let coerced = false;\n let other = false;\n\n // @ts-ignore - see above\n for (const [value, found] of column.byValue) {\n if (typeof found !== 'number' && standsForSeveral(found, numbers, texts)) {\n // Under a value that is a number, every symbol with a number has that number, so what disagrees with\n // them is a pure string - and only coercion reads a pure string as a number.\n if (typeof value === 'number') {\n coerced = true;\n } else {\n other = true;\n }\n }\n }\n\n if (!coerced) {\n return \"Read the field with {duals: 'both'}, or write QvdDual cells.\";\n }\n\n // A value that is a string, and stands for several stored values, is a dual's text a 'text' read\n // showed, and dropping coercion leaves it as ambiguous as it was.\n // @ts-ignore - see above\n if (!other && !ambiguousAsUncoercedText(column.entry)) {\n return 'Read the field without {coerceNumericStrings: true}.';\n }\n\n if (unambiguousWithoutDuals(column)) {\n return \"Read the field with {duals: 'both'}.\";\n }\n\n // A dual shown as its text shows a 'text' read, and every value `other` counted is one.\n return values.some((value, index) => typeof value === 'string' && numbers[index] !== null)\n ? \"Read the field with {duals: 'both'} and without {coerceNumericStrings: true}.\"\n : \"Read the field without {coerceNumericStrings: true}, and with {duals: 'both'} as well if it was read \" +\n \"with {duals: 'text'}.\";\n}\n\n/**\n * The slot for a number or a string cell the column has not seen, through the frame's record.\n *\n * With no record entry for the value, the cell is its own key. Otherwise the entries holding it say\n * what it stands for: one pure string's text, or one number with the first text any of them has. When\n * they say more than one thing - two numbers, two texts, or a number and a string - the cell could be\n * either, and it is refused rather than written as one of them.\n *\n * The ambiguity is worked out here, from the entries themselves, rather than trusted to a read: a\n * record merged from two frames, or built by hand, is checked the same way. An entry whose every value\n * is its own number - see `valuesAreNumbers` - has no ambiguity to find, so the cell only takes its text.\n *\n * Called only for a cell the row loop has just looked for in `byCell` and not found, and whose slot the\n * row loop then puts there.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} value The cell.\n * @param {number} row The row, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {number} The slot.\n * @throws {QvdValidationError} If the record maps the value to more than one stored value.\n */\nfunction slotForCell(column, value, row, filePath) {\n // A cell that is its own key. `byCell` is `byKey` here, so the lookup that missed was for the key: the\n // slot is new, and the row loop's write of it is the write to `byKey`. Asking again, and writing twice,\n // cost two map operations per distinct value.\n if (column.byCell === column.byKey) {\n return newSlot(column, value, column.textByNumber === null ? null : (column.textByNumber.get(value) ?? null));\n }\n\n // @ts-ignore - a column whose cells have a map of their own has an entry that is not keyed by numbers\n const found = column.byValue.get(value);\n\n if (found === undefined) {\n return slotFor(column, value, null);\n }\n\n // @ts-ignore - byValue is only set together with entry\n const {numbers, texts} = column.entry;\n const indices = typeof found === 'number' ? [found] : found;\n\n if (standsForSeveral(indices, numbers, texts)) {\n /** @type {Array<{number: number|null, text: string|null}>} */\n const stored = [];\n\n for (const index of indices) {\n if (!stored.some((pair) => sameValueZero(pair.number, numbers[index]) && pair.text === texts[index])) {\n stored.push({number: numbers[index], text: texts[index]});\n }\n }\n\n throw new QvdValidationError(\n `The value ${JSON.stringify(value)} in field '${column.name}' (row ${row}) was read from ${stored.length} ` +\n `different stored values, so writing it back would have to guess which one. ${ambiguityRemedy(column)}`,\n {column: column.name, row, value, stored, file: filePath, stage: 'buildSymbolTable'},\n );\n }\n\n /** @type {number|null} */\n let number = null;\n /** @type {string|null} */\n let numberText = null;\n\n for (const index of indices) {\n // One stored value: a pure string here means every symbol holding the value is that string.\n if (numbers[index] === null) {\n // @ts-ignore - a symbol with no number has a text\n return slotFor(column, texts[index], null);\n }\n\n number ??= numbers[index];\n numberText ??= texts[index];\n }\n\n // @ts-ignore - every index came from an entry that holds a number or a text, and none was a string\n return slotFor(column, number, numberText);\n}\n\n/**\n * The slot for a dual object the column has not remembered.\n *\n * Keyed by its number, so a fresh object per row costs a validation and a lookup, and never a map\n * entry past the bound. Anything that is not a dual - see `asDual` - is refused.\n *\n * @param {ColumnSymbols} column The column.\n * @param {object} value The cell.\n * @param {number} row The row, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {number} The slot.\n * @throws {QvdValidationError} If the value is not a dual, or a half of it cannot be stored.\n */\nfunction slotForObject(column, value, row, filePath) {\n const dual = asDual(value);\n\n if (dual === null) {\n refuseCell(value, column.name, row, filePath);\n }\n\n const {number, text} = dual;\n\n // The problem functions allocate nothing for a good half, so the context is only built for a bad one.\n if (numberProblem(number) !== null) {\n checkNumber(number, 'The number of a dual value', {\n column: column.name,\n row,\n half: 'number',\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n if (textProblem(text) !== null) {\n checkText(text, 'The text of a dual value', {\n column: column.name,\n row,\n half: 'text',\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n const slot = slotFor(column, number, text);\n\n if (column.byObject.size < OBJECT_MEMO_BASE + 2 * column.keys.length) {\n column.byObject.set(value, slot);\n }\n\n return slot;\n}\n\n/** Tags that only hold while every value in the field has a number. */\nconst NUMERIC_TAGS = new Set(['$numeric', '$integer', '$date', '$time', '$timestamp']);\n\n/** Tags that only hold while every value in the field is plain text. */\nconst TEXT_TAGS = new Set(['$text', '$ascii']);\n\n/** Tags that only hold while every number in the field is a whole number. */\nconst WHOLE_NUMBER_TAGS = new Set(['$integer', '$date']);\n\n/** Number formats that describe how Qlik displays a number, and so mean nothing on a text field. */\nconst NUMERIC_FORMATS = new Set(['INTEGER', 'REAL', 'FIX', 'MONEY', 'DATE', 'TIME', 'TIMESTAMP', 'INTERVAL']);\n\n/** What a field with no number format of its own is written with. */\nconst UNKNOWN_NUMBER_FORMAT = Object.freeze({Type: 'UNKNOWN', nDec: '0', UseThou: '0', Fmt: '', Dec: '', Thou: ''});\n\n/**\n * The field's tags, less any the written values contradict.\n *\n * Tags are carried from the header a frame was read with, and a caller can change a field's values\n * without touching its tags - read a timestamp field with `{duals: 'text'}` and write it back, and the\n * values are text while the header still says `$numeric` and `$timestamp`, which tells Qlik a text\n * field is numeric. So a tag the values contradict is dropped:\n *\n * - a value with no number drops `$numeric`, `$integer`, `$date`, `$time` and `$timestamp`;\n * - a number that is not whole drops `$integer` and `$date`;\n * - any number drops `$text` and `$ascii`.\n *\n * The definitions are Qlik's field-tag help: `$numeric` - every non-NULL value is numeric; `$integer`\n * - every value is an integer; `$date` - every value can be read as a date, which it defines as an\n * integer; `$text` - no value is numeric. The bundled Qlik files agree where they can: `$text` and\n * `$ascii` appear only on fields whose every value is a pure string, and a field mixing strings and\n * numbers carries neither. They also show what not to derive. Qlik keeps `$ascii` on fields holding\n * characters outside ASCII - their first such value is always past the hundredth symbol, so it looks\n * like a judgement from the first values rather than all of them - and keeps `$timestamp` on a field of\n * timestamps some of which fall exactly on midnight, so a whole number does not contradict it. The\n * reference files in `docs/reference-qvds/` carry `$date`, and only on fields whose every number is\n * whole, which is what the `$date` rule assumes. No file carries `$time`, not even a field Qlik built\n * with `Time()`, so that rule still rests on the help alone.\n *\n * Only removes, never adds. A tag Qlik would have added is Qlik's to add on its next load; inventing\n * one here would be the writer asserting something it has no way to know - `$date` over an integer\n * field, say. `$key`, `$hidden` and custom tags pass through.\n *\n * @param {any} tags The field's tags as carried in the metadata: `{String: string | string[]}`, or\n * something else, which is returned untouched.\n * @param {SlotFacts|undefined} facts What the field's written symbols hold.\n * @return {any} The tags to write.\n */\nfunction pruneContradictedTags(tags, facts) {\n if (tags === null || typeof tags !== 'object' || tags.String === undefined || facts === undefined) {\n return tags || {};\n }\n\n const list = Array.isArray(tags.String) ? tags.String : [tags.String];\n const kept = list.filter((/** @type {string} */ tag) => {\n if (facts.hasNonNumber && NUMERIC_TAGS.has(tag)) return false;\n if (facts.hasFraction && WHOLE_NUMBER_TAGS.has(tag)) return false;\n if (facts.hasNumber && TEXT_TAGS.has(tag)) return false;\n return true;\n });\n\n if (kept.length === list.length) {\n return tags;\n }\n\n return kept.length === 0 ? {} : {...tags, String: kept};\n}\n\n/**\n * The field's number format, reset when the field no longer holds a number to apply it to.\n *\n * A `DATE` or `MONEY` format on a field whose values are all text describes nothing, and misleads\n * whoever reads the header next. A field that still has a single number keeps its format: Qlik's own\n * files carry `REAL` on a field holding only the integer 0 and `MONEY` on fields where some amounts are integers,\n * so no other mismatch is a contradiction.\n *\n * @param {any} numberFormat The field's number format as carried in the metadata.\n * @param {SlotFacts|undefined} facts What the field's written symbols hold.\n * @return {any} The number format to write.\n */\nfunction resetContradictedNumberFormat(numberFormat, facts) {\n if (!numberFormat) {\n return {...UNKNOWN_NUMBER_FORMAT};\n }\n\n if (facts !== undefined && !facts.hasNumber && facts.hasNonNumber && NUMERIC_FORMATS.has(numberFormat.Type)) {\n return {...UNKNOWN_NUMBER_FORMAT};\n }\n\n return numberFormat;\n}\n\n/**\n * Maximum length of a single fs.write call. Node checks that a write's length fits in an Int32 and\n * rejects one of 2 GiB or more with a RangeError, so a symbol or index table that large could not be\n * written in one call at all. QvdFileReader caps its reads at the same size, and there an oversized\n * length aborts the process rather than throwing.\n */\nconst WRITE_CHUNK_SIZE = 512 * 1024 * 1024;\n\nexport class QvdFileWriter {\n /**\n * Constructs a new QVD file writer.\n *\n * @param {string} filePath The path to the QVD file to write.\n * @param {QvdDataFrame} df The data frame to write to the QVD file.\n * @param {Object} [options={}] Options for the writer.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function.\n * @param {boolean} [options.atomic=true] Whether to replace the destination rather than rewrite it:\n * the file is built beside it under a temporary name and renamed over it, so a failure leaves the\n * previous file exactly as it was and nothing ever reads a part-written one. False rewrites the\n * destination in place, which is what every version before 2.0.0 did: that keeps the file's\n * identity - hard links, its owner, permissions set on the file itself - needs no room for two\n * copies at once and no permission to create files in the directory, and destroys the previous\n * file the moment the write begins. A file that does not exist yet is renamed into place either\n * way, since there is nothing to rewrite - see `_destination`.\n * @param {boolean} [options.fsync=true] Whether to wait for the file's contents to reach the disk\n * before the write is finished. It is what carries an atomic write's promise through a power\n * loss - the contents are on the disk before anything is renamed, so a crash leaves the previous\n * file or the new one and never a damaged one - and it is the only thing that reports a failing\n * disk's deferred error rather than losing it. The rename itself is not flushed, so a crash just\n * after the call can still lose the replacement, or a file that did not exist before. False\n * resolves as soon as the operating system has accepted the bytes, which is faster and is what\n * every version before 2.0.0 did.\n */\n constructor(filePath, df, options = {}) {\n const {allowedDir, onProgress, atomic, fsync} = options;\n const checked = checkPath(filePath, allowedDir);\n this._path = checked.path;\n /**\n * The allowed directory, resolved. Kept because the path is checked again immediately before the\n * file is written - see `_destination` - and building the tables first can take seconds, which is\n * a long time for a path to go unwatched. That check is made against the directory this one was.\n */\n this._allowedDir = checked.base;\n // Unset means on for both: a null out of optional configuration or a JSON round trip must not\n // quietly become the way that loses the previous file. `booleanOption` says the rest.\n this._atomic = booleanOption(atomic, {option: 'atomic', file: this._path, whenUnset: true});\n this._fsync = booleanOption(fsync, {option: 'fsync', file: this._path, whenUnset: true});\n this._df = df;\n this._onProgress = onProgress;\n this._header = null;\n this._symbolBuffer = null;\n /**\n * Symbols written per column. It used to be the symbols themselves, as QvdSymbol objects, kept\n * alive through the header build and the file write for the sake of their count.\n *\n * @type {Array<number>|null}\n */\n this._symbolCounts = null;\n /** @type {Array<SlotFacts>|null} What each column's symbols hold, for pruning its tags. */\n this._symbolFacts = null;\n /** @type {Array<any>|null} */\n this._symbolTableMetadata = null;\n this._indexBuffer = null;\n /**\n * How each column's cells find their stored index: the slot maps `_buildSymbolTable` built.\n *\n * Built while the symbol table is, because that pass already decides the order symbols are\n * written in and therefore what each index is. The alternative - re-deriving it here from\n * a QvdSymbol and a template-literal key per cell - meant converting every cell twice and\n * allocating 34 million strings on the taxi fixture to look up something already known.\n *\n * @type {Array<{byCell: Map<number|string, number>, byKey: Map<number|string, number>,\n * byObject: Map<object, number>}>|null}\n */\n this._symbolIndexByValue = null;\n /** @type {Array<any>|null} */\n this._indexTableMetadata = null;\n /** Rows written, kept because the index table is no longer an array to count. @type {number} */\n this._recordCount = 0;\n this._recordByteSize = null;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * @param {string} stage The current stage of the operation.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n this._onProgress({\n stage,\n current,\n total,\n percent,\n });\n }\n }\n\n /**\n * Writes the data to the QVD file.\n */\n async _writeData() {\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolBuffer, 'The QVD file symbol table has not been parsed.');\n assert(this._indexBuffer, 'The QVD file index table has not been parsed.');\n\n this._emitProgress('write', 0, 1);\n\n // @ts-ignore - Buffer.concat type compatibility\n const headerBuffer = Buffer.concat([Buffer.from(this._header, 'utf-8'), Buffer.from([0])]);\n\n // Every file-system call below goes through this, so a missing directory, a permission error or\n // a write the disk refuses is a QvdIOError carrying the system code rather than Node's bare error.\n // The close included: a network share can report a write's failure only when the file is closed.\n // `context.file` is the path the caller named even where the call that failed was made on the\n // temporary file, which is the file they asked to write; Node's own message, kept whole, names it.\n const failed = rethrowAsIoError(this._path, 'write');\n const destination = this._destination();\n\n if (destination.replace) {\n await this._replaceFile(destination, headerBuffer, failed);\n } else {\n await this._writeInPlace(destination, headerBuffer, failed);\n }\n\n // Reported once the file is in place rather than once the last byte has been accepted, so a write\n // that then fails to be flushed, closed or renamed has not already said it finished.\n this._emitProgress('write', 1, 1);\n }\n\n /**\n * What is at the destination, and therefore how it is to be written.\n *\n * Decided by one containment check, made now - immediately before anything is opened - and by\n * nothing else: the file that check approved is the file written, in either mode, and what the\n * check found there is what decides how.\n *\n * It used to stat and resolve the path again for itself, after the check. That second resolution\n * was #247 in the atomic write: a destination swapped for a symlink after the check was followed by\n * it, so the temporary file was built beside a file outside allowedDir and renamed over it. A check\n * reports where it went, so nothing here has to go there again.\n *\n * @return {{checked: import('./util/validatePath.js').CheckedPath, path: string,\n * existing: import('fs').BigIntStats|null, replace: boolean, sync: boolean}} The check, the file it\n * approved, what was there, whether to replace it rather than rewrite it, and whether to flush it.\n * @private\n */\n _destination() {\n // The file an open of the path reaches - its canonical path, so a symlink at the destination is\n // followed and kept, the file at its end replaced; or, where nothing exists yet, the name at the far\n // end of any dangling links, which is where an open() of the path would create it. Both write\n // modes use this one answer, so they agree about which file a symlink names.\n const checked = checkPath(this._path, this._allowedDir);\n const existing = checked.stats;\n\n // A destination that exists and is not a regular file is written in place whatever was asked for,\n // and never flushed. Replacing a device or a FIFO would replace the device: a root process writing\n // to /dev/null would leave a QVD where /dev/null was. A directory is refused rather than written:\n // by the open on POSIX, and on Windows - which opens a directory for writing when it is not also\n // asked to empty it - by the first write, before any byte lands. And fsync on something that is not\n // a file is EINVAL, which would fail a write that is otherwise fine.\n const special = existing !== null && !existing.isFile();\n\n // A name nothing is at yet is written by building the file beside it and renaming it there, in\n // either mode. There is nothing to rewrite, so the file that results is the one an in-place write\n // would have made - and a rename replaces the name rather than following anything at it, which an\n // open that creates cannot promise: on Windows even O_EXCL follows a dangling symlink planted at\n // the name, and creates the file wherever it points. So the in-place write is only ever a rewrite\n // of a file that exists, and `openChecked` is only asked to rewrite one it can hold to an identity.\n const replace = (this._atomic || existing === null) && !special;\n\n return {\n checked,\n path: checked.target,\n existing,\n replace,\n sync: this._fsync && !special,\n };\n }\n\n /**\n * Rewrites the destination where it stands - the way every version before 2.0.0 wrote.\n *\n * The file is emptied as the write begins, so from there until the last byte is written there is no\n * previous version left: a failure part-way through leaves a stub that no read of its rows survives,\n * and anything reading the path meanwhile sees however much of the new file has arrived.\n *\n * It is emptied by `openChecked` rather than by opening with `'w'`, and later than `'w'` would: once\n * the descriptor is known to be the file the check approved. `'w'` empties whatever the open reaches,\n * which is what let #247 truncate a file outside allowedDir through a symlink swapped in after the\n * check. The file that results is the same.\n *\n * @param {{checked: import('./util/validatePath.js').CheckedPath, sync: boolean}} destination Where\n * to write, from `_destination`.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _writeInPlace(destination, headerBuffer, failed) {\n // Closed by `closeAfter` rather than in a `finally`, so a close that fails after a write already\n // has cannot replace the write's error - the ENOSPC that explains the failure, not the close's EIO.\n const fd = await openChecked(destination.checked, 'rewrite', failed);\n\n await closeAfter(fd, failed, async () => {\n await this._writeParts(fd, headerBuffer, failed);\n\n if (destination.sync) {\n await fd.sync().catch(failed);\n }\n });\n }\n\n /**\n * Builds the file beside the destination and renames it over it.\n *\n * Nothing touches the destination until the rename, which either replaces it or leaves it as it was,\n * so a write that fails at any step - a full disk, a process killed, an error from the disk itself -\n * costs the temporary file and nothing else. A reader of the path gets the previous file or the new\n * one, never a part of either, which is the other half of what the old behaviour could not promise.\n *\n * @param {{path: string, existing: import('fs').BigIntStats|null, sync: boolean}} destination Where to\n * write, from `_destination`.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _replaceFile(destination, headerBuffer, failed) {\n const temporary = temporaryPathFor(destination.path);\n // 'wx' rather than 'w', so a name that somehow exists already is never written through. A\n // temporary standing in for a file that exists is created private and given that file's\n // permissions once it is whole: Node creates a file 0666 less the umask, which on a usual machine\n // would leave a half-written copy of a 0600 QVD readable by everyone until the chmod below, and\n // longer if its removal fails. A destination that does not exist yet gets the ordinary mode, which\n // is what a write of a new file has always produced.\n const mode = destination.existing === null ? undefined : 0o600;\n const fd = await fs.promises.open(temporary, 'wx', mode).catch(failed);\n\n try {\n await closeAfter(fd, failed, async () => {\n await this._writeParts(fd, headerBuffer, failed);\n\n // The file that appears keeps the permissions of the one it replaces. Through the handle\n // rather than as the open's mode, which the process umask masks. Not on Windows, where the\n // mode is the read-only attribute and nothing else: copying that would leave a temporary file\n // Windows then refuses to rename or to remove.\n if (destination.existing !== null && process.platform !== 'win32') {\n // The check's stats are BigInts - identity needs every bit of a Windows file ID - so the mode\n // is converted before it is masked: a BigInt and a Number do not mix in `&`.\n await fd.chmod(Number(destination.existing.mode) & 0o777).catch(failed);\n }\n\n // Before the rename, not after it, so that what a crash can lose is the replacement and never\n // the contents: the destination is the old file or the new one, whenever the power goes.\n if (destination.sync) {\n await fd.sync().catch(failed);\n }\n });\n\n await renameOver(temporary, destination.path).catch(failed);\n } catch (error) {\n // The destination has not been touched, so the temporary file is all this attempt leaves.\n const removed = await removeTemporary(temporary);\n\n // The removal can be refused too - on Windows while something else still holds the file open.\n // The error on its way out is the one that explains the write, so it is not replaced; the file\n // left behind is named in its context instead, which is the only way a caller could learn of it.\n //\n // Only where that context will take it. A module is strict code, so assigning to a frozen or\n // sealed object throws, and an error about the tidying up would then replace the ENOSPC that\n // explains the write - which is the whole point of `closeAfter`, undone at the last step. No\n // error reaching here carries a frozen context today; this is so that none ever can.\n const context = /** @type {{context?: Record<string, unknown>}} */ (error)?.context;\n if (!removed && context !== null && typeof context === 'object' && Object.isExtensible(context)) {\n context.temporaryFile = temporary;\n }\n\n throw error;\n }\n }\n\n /**\n * Writes the three parts of a QVD, in their order, into an open file.\n *\n * @param {import('fs/promises').FileHandle} fd The open file.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _writeParts(fd, headerBuffer, failed) {\n await this._writeRange(fd, headerBuffer, 0, failed);\n await this._writeRange(fd, this._symbolBuffer, headerBuffer.length, failed);\n await this._writeRange(fd, this._indexBuffer, headerBuffer.length + this._symbolBuffer.length, failed);\n }\n\n /**\n * Writes the whole of one buffer into the file, starting at `filePosition`.\n *\n * A write can resolve having written less than it was given, and that is all a disk that fills\n * part-way through one says. libuv retries a short write(2) itself, and when the retry fails it\n * returns the bytes that did land instead of the error - `uv__fs_write_all` in its `src/unix/fs.c`,\n * and `fs__write` on Windows does the same - so Node resolves with a short `bytesWritten` and never\n * rejects. Taking that for the whole write is how `toQvd()` resolved on a full disk and left a\n * truncated file: the index table, the last of the three writes, stopped part-way, and no later call\n * asked the disk again.\n *\n * So the rest is written until there is none, and it is the next call that reports the failure: the\n * disk refuses it outright, and that rejection is a QvdIOError with the system's code, ENOSPC, like\n * any other refused write. A write that stores nothing and reports nothing would repeat forever, so\n * it is a failure too, the one QvdIOError with no system code to carry.\n *\n * In bounded chunks as well, because Node refuses a single write of 2 GiB or more.\n *\n * @param {import('fs/promises').FileHandle} fd The open file.\n * @param {Buffer} buffer What to write.\n * @param {number} filePosition Where in the file it starts.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler, which every call\n * goes through.\n * @private\n */\n async _writeRange(fd, buffer, filePosition, failed) {\n let done = 0;\n\n while (done < buffer.length) {\n const length = Math.min(WRITE_CHUNK_SIZE, buffer.length - done);\n const {bytesWritten} = await fd.write(buffer, done, length, filePosition + done).catch(failed);\n\n // Not `=== 0`: a count that is not a positive number - from a patched `fs`, say - would make\n // `done` NaN and end the loop as though the part were written, which is this bug over again.\n if (!(bytesWritten > 0)) {\n throw new QvdIOError(\n `Could not write the QVD file: nothing was written at byte ${filePosition + done}, ` +\n 'and the operating system reported no error.',\n {file: this._path, operation: 'write', filePosition: filePosition + done},\n );\n }\n\n done += bytesWritten;\n }\n }\n\n /**\n * Builds the XML header of the QVD file.\n */\n _buildHeader() {\n this._emitProgress('header', 0, 1);\n const creationDate = new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '');\n /** @type {import('./QvdDataFrame.js').QvdMetadata|null} */\n const existingMetadata = this._df.metadata;\n\n // Use existing metadata if available, otherwise create default values\n const baseMetadata = existingMetadata\n ? {\n QvBuildNo: existingMetadata.QvBuildNo || 50667,\n CreatorDoc: existingMetadata.CreatorDoc || crypto.randomUUID(),\n CreateUtcTime: existingMetadata.CreateUtcTime || creationDate,\n SourceCreateUtcTime: existingMetadata.SourceCreateUtcTime || '',\n SourceFileUtcTime: existingMetadata.SourceFileUtcTime || '',\n SourceFileSize: existingMetadata.SourceFileSize || -1,\n StaleUtcTime: existingMetadata.StaleUtcTime || '',\n TableName: existingMetadata.TableName || path.basename(this._path, path.extname(this._path)),\n Compression: existingMetadata.Compression || '',\n Comment: existingMetadata.Comment || '',\n EncryptionInfo: existingMetadata.EncryptionInfo || '',\n TableTags: existingMetadata.TableTags || '',\n ProfilingData: existingMetadata.ProfilingData || '',\n Lineage: existingMetadata.Lineage || {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n }\n : {\n QvBuildNo: 50667,\n CreatorDoc: crypto.randomUUID(),\n CreateUtcTime: creationDate,\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: path.basename(this._path, path.extname(this._path)),\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n };\n\n // Get existing field metadata if available\n /** @type {any[]} */\n let existingFields = [];\n if (existingMetadata && existingMetadata.Fields && existingMetadata.Fields.QvdFieldHeader) {\n existingFields = Array.isArray(existingMetadata.Fields.QvdFieldHeader)\n ? existingMetadata.Fields.QvdFieldHeader\n : [existingMetadata.Fields.QvdFieldHeader];\n }\n\n const xmlObject = {\n QvdTableHeader: {\n ...baseMetadata,\n Fields: {\n QvdFieldHeader: this._df.columns.map((/** @type {any} */ column, /** @type {number} */ index) => {\n // Find existing field metadata for this column\n const existingField = existingFields.find((/** @type {any} */ f) => f.FieldName === column);\n\n return {\n FieldName: column,\n BitOffset: this._indexTableMetadata?.[index][0],\n BitWidth: this._indexTableMetadata?.[index][1],\n Bias: this._indexTableMetadata?.[index][2],\n NoOfSymbols: this._symbolCounts?.[index],\n Offset: this._symbolTableMetadata?.[index][0],\n Length: this._symbolTableMetadata?.[index][1],\n Comment: existingField?.Comment || '',\n NumberFormat: resetContradictedNumberFormat(existingField?.NumberFormat, this._symbolFacts?.[index]),\n Tags: pruneContradictedTags(existingField?.Tags, this._symbolFacts?.[index]),\n };\n }),\n },\n NoOfRecords: this._recordCount,\n RecordByteSize: this._recordByteSize,\n Offset:\n this._symbolTableMetadata && this._symbolTableMetadata.length > 0\n ? this._symbolTableMetadata[this._symbolTableMetadata.length - 1][0] +\n this._symbolTableMetadata[this._symbolTableMetadata.length - 1][1]\n : 0,\n Length: this._indexBuffer?.length,\n },\n };\n\n // Every text the builder is about to write, so a character XML cannot hold is refused naming the\n // property it is in. The field names were checked before the rows were.\n const {Fields, ...table} = xmlObject.QvdTableHeader;\n\n for (const [property, value] of Object.entries(table)) {\n checkHeaderTexts(value, property, 'the table', {file: this._path, stage: 'buildHeader'});\n }\n\n for (const {FieldName, ...field} of Fields.QvdFieldHeader) {\n for (const [property, value] of Object.entries(field)) {\n checkHeaderTexts(value, property, `field '${FieldName}'`, {\n column: FieldName,\n file: this._path,\n stage: 'buildHeader',\n });\n }\n }\n\n const builder = new xml.Builder({\n renderOpts: {\n pretty: true,\n newline: '\\r\\n',\n indent: ' ',\n },\n });\n this._header = builder.buildObject(xmlObject) + '\\r\\n';\n this._emitProgress('header', 1, 1);\n }\n\n /**\n * Builds the symbol table of the QVD file.\n *\n * One pass over the rows finds each column's distinct values in the order they first appear,\n * which is the order Qlik lists symbols in, and checks each distinct value once. A second pass per\n * column encodes them: every symbol is sized first, then written into one buffer of exactly that\n * size.\n *\n * What each value is stored as:\n *\n * | Cell | Symbol |\n * | --- | --- |\n * | `null`, `undefined`, a hole, a missing cell | none - the field's `Bias` records NULL |\n * | an integer from -2147483648 to 2147483647, -0 included | pure int, type 1 |\n * | any other finite number | pure double, type 2 |\n * | a string | pure string, type 4 |\n * | a dual - a `QvdDual`, or an object whose only keys are `number` and `text` | dual int or dual double, type 5 or 6, by the number |\n * | a number or a string the frame's `storedSymbols` records | the symbol it was read from |\n *\n * A number is a pure number, with no text. It used to be written as a dual whose text was\n * `String(value)`, which was wrong twice over: it invented text the caller never supplied, and a\n * file Qlik wrote with pure numbers came back out of a read and a write with every one of them\n * turned into a dual. The kind follows `isStoredAsInt`, which is the rule Qlik's own files follow.\n * A string is never parsed, so `'7'` and `7` in one column are two symbols. It is stored as its\n * UTF-8 bytes, or refused where those bytes would not give it back: a NUL ends a stored text, and\n * an unpaired surrogate has no UTF-8 encoding at all.\n *\n * A column holds one symbol per number, as a Qlik field does. Several duals with one number are one\n * symbol with the first text in row order, and a plain number with the same number as a dual joins\n * the dual, in either order - so no text a caller supplied is lost to a plain number that came\n * first. A string is not a number, so a string equal to a dual's text is a symbol of its own.\n *\n * A frame read from a file shows one half of some symbols: a dual read as its number or its text, a\n * string read as a number. Its record says what each such cell stands for, so the frame writes back\n * the symbols it was read from - the dual's text, Qlik's exact double, the string `'007'` - whichever\n * rows the cells were moved to. A cell the record maps to more than one stored value is refused.\n *\n * The complexity claim is the one to trust here: O(rows x columns) for the pass, and O(symbols)\n * for the encoding. The \"80-90% improvement\" this comment once carried is not reproducible in this\n * repository; `benchmarks/` measures what the writer costs now, which is the useful number.\n *\n * @private\n */\n _buildSymbolTable() {\n this._symbolCounts = [];\n this._symbolFacts = [];\n this._symbolTableMetadata = [];\n this._symbolIndexByValue = [];\n\n // A table with no fields is not a QVD. Writing one produced a 741-byte file with an empty\n // `<Fields/>` element that this same library refuses to load, which is the worst of both:\n // the write reports success and the failure surfaces later, somewhere else.\n if (this._df.columns.length === 0) {\n throw new QvdValidationError('A QVD file must have at least one field', {\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numColumns = columns.length;\n const numRows = data.length;\n\n validateColumnNames(columns, this._path);\n\n // Through the same check a frame's constructor applies, which costs nothing for a record that came\n // from a read or was already checked, and refuses a malformed one handed to the writer directly.\n const record = normaliseStoredSymbols(this._df.storedSymbols);\n\n this._emitProgress('symbol-table', 0, numColumns);\n\n // Per column, the slots in first-appearance order and the maps that find them - see\n // ColumnSymbols. A Map compares keys by SameValueZero, so a number is one symbol however many rows\n // hold it, and 0 and -0 in one column are one symbol - which isStoredAsInt stores as the integer 0\n // either way.\n //\n // No third structure: this used to be a Set per column, then `Array.from` on it, then a Map built\n // from the array, three structures each holding a reference to every distinct value. On a column\n // whose values are all distinct that was roughly 30MB of duplication per million rows.\n /** @type {Array<ColumnSymbols>} */\n const state = columns.map((/** @type {string} */ name) => {\n const entry = record === null ? null : (record.find((candidate) => candidate.field === name) ?? null);\n /** @type {Map<number|string, number>} */\n const byKey = new Map();\n /** @type {Map<number|string, number|Array<number>>|null} */\n let byValue = null;\n /** @type {Map<number|string, string>|null} */\n let textByNumber = null;\n\n if (entry !== null && valuesAreNumbers(entry)) {\n textByNumber = firstTextByValue(entry);\n } else if (entry !== null) {\n byValue = new Map();\n\n // An index per value, and an array only for a value two entries share, which a record read from\n // a Qlik file never has: a field of distinct duals costs a map entry per value, not an array.\n for (let index = 0; index < entry.values.length; index++) {\n const found = byValue.get(entry.values[index]);\n\n if (found === undefined) {\n byValue.set(entry.values[index], index);\n } else if (typeof found === 'number') {\n byValue.set(entry.values[index], [found, index]);\n } else {\n found.push(index);\n }\n }\n }\n\n return {\n name,\n keys: [],\n texts: [],\n byKey,\n // A cell is its own key without a record entry, and with one whose values are their numbers, so\n // one Map serves both. On a field of distinct duals that is a map entry per symbol fewer.\n byCell: entry === null || textByNumber !== null ? byKey : new Map(),\n byObject: new Map(),\n entry,\n textByNumber,\n byValue,\n facts: {hasNumber: false, hasNonNumber: false, hasFraction: false},\n };\n });\n\n // Hoisted out of the column objects, so the row loop's common case - a value the column has seen\n // - is an array read and a Map lookup, as it was before the column had anything else to keep.\n const byCells = state.map((column) => column.byCell);\n const byObjects = state.map((column) => column.byObject);\n /** @type {Array<boolean>} */\n const containsNull = columns.map(() => false);\n\n // A counted loop, not `data.forEach`. forEach skips array holes and the index table's loop\n // does not, so a sparse `data` array made the two passes disagree about how many rows\n // exist: a five-element array with one row set wrote a five-row file in which four rows\n // carried a real value copied from the fifth, and a hole between two rows threw a bare\n // TypeError. A hole reads as `undefined`, which is what this writer already treats as NULL\n // everywhere else, so both passes now see the same rows and a hole becomes a NULL row.\n for (let row = 0; row < numRows; row++) {\n const values = data[row];\n\n // A missing row is a row of NULLs, which is what a hole in a sparse array already means.\n // A row that is present but is not an array is different: `values?.[column]` reads\n // `undefined` from it for every column, so `{columns: ['a'], data: [1, 2]}` used to write a\n // two-row file of NULLs and report success, discarding everything the caller passed.\n if (values !== null && values !== undefined && !Array.isArray(values)) {\n throw new QvdValidationError('Each row must be an array of values', {\n row,\n type: typeof values,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n // A short row is padded with NULLs, deliberately. A long one is not truncated, because\n // dropping the extra cells silently is how a caller whose columns and data have drifted\n // apart gets a plausible file with a column missing.\n if (values !== null && values !== undefined && values.length > numColumns) {\n throw new QvdValidationError(`Row ${row} has ${values.length} values but there are ${numColumns} fields`, {\n row,\n values: values.length,\n fields: numColumns,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n containsNull[column] = true;\n continue;\n }\n\n // A dual object is looked up by identity in its own map, so the primitive map is never asked\n // about an object it cannot hold.\n if (typeof value === 'object') {\n if (!byObjects[column].has(value)) {\n slotForObject(state[column], value, row, this._path);\n }\n\n continue;\n }\n\n // A primitive the column has already seen costs this one lookup, as it did before duals.\n if (byCells[column].has(value)) {\n continue;\n }\n\n // Once per distinct value, not once per row: a repeat has already been through this. The\n // problem functions allocate nothing for a good value, so the context object is only built\n // for a value that is about to be refused.\n if (typeof value === 'number') {\n if (numberProblem(value) !== null) {\n checkNumber(value, null, {column: columns[column], row, file: this._path, stage: 'buildSymbolTable'});\n }\n } else if (typeof value === 'string') {\n if (textProblem(value) !== null) {\n checkText(value, 'A string value', {\n column: columns[column],\n row,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n } else {\n refuseCell(value, columns[column], row, this._path);\n }\n\n byCells[column].set(value, slotForCell(state[column], value, row, this._path));\n }\n }\n\n // Serialised per column and concatenated once. Concatenating onto an accumulating buffer\n // instead re-copies every byte written so far on each column - O(bytes x columns), which\n // measured 26ms against 14ms on a 67MB symbol table and gets worse linearly with the column\n // count, while transiently holding two copies of everything written so far.\n /** @type {Array<Buffer>} */\n const columnBuffers = [];\n let symbolsOffset = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const {keys, texts} = state[column];\n const kinds = new Uint8Array(keys.length);\n let byteLength = 0;\n\n for (let slot = 0; slot < keys.length; slot++) {\n const key = keys[slot];\n const text = texts[slot];\n\n if (typeof key === 'number') {\n // Both halves were checked when the cell was, or when the record was; this is the last look\n // before the bytes are written. A record a read built is taken as the file stored it, so a\n // damaged file's NaN dual read as its text reaches a slot only through the record - and is\n // refused here as the NaN cell it stands for would have been.\n if (numberProblem(key) !== null) {\n checkNumber(key, null, {column: columns[column], file: this._path, stage: 'buildSymbolTable'});\n }\n\n if (text !== null && textProblem(text) !== null) {\n checkText(text, 'The text of a dual value', {\n column: columns[column],\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n kinds[slot] = kindOf(key, text);\n byteLength += symbolByteLength(kinds[slot], key, text);\n } else {\n kinds[slot] = kindOf(null, key);\n byteLength += symbolByteLength(kinds[slot], null, key);\n }\n }\n\n // allocUnsafe, because every byte is about to be written. The assertion below holds it to that:\n // a byte left unwritten would carry whatever memory the buffer was given into the file.\n const columnBuffer = Buffer.allocUnsafe(byteLength);\n let offset = 0;\n\n for (let slot = 0; slot < keys.length; slot++) {\n const key = keys[slot];\n\n offset =\n typeof key === 'number'\n ? writeSymbol(columnBuffer, offset, kinds[slot], key, texts[slot])\n : writeSymbol(columnBuffer, offset, kinds[slot], null, key);\n }\n\n assert(offset === byteLength, 'A column was encoded into a different number of bytes than it was sized for.');\n\n columnBuffers.push(columnBuffer);\n this._symbolTableMetadata?.push([symbolsOffset, byteLength, containsNull[column]]);\n this._symbolCounts?.push(keys.length);\n this._symbolFacts?.push(state[column].facts);\n this._symbolIndexByValue?.push({\n byCell: state[column].byCell,\n byKey: state[column].byKey,\n byObject: state[column].byObject,\n });\n\n symbolsOffset += byteLength;\n\n this._emitProgress('symbol-table', column + 1, numColumns);\n }\n\n // @ts-ignore - Buffer.concat type compatibility\n this._symbolBuffer = Buffer.concat(columnBuffers);\n }\n\n /**\n * Builds the bit-packed index table of the QVD file.\n *\n * A record is `recordByteSize` bytes. Each column occupies `bitWidth` consecutive bits at\n * `bitOffset`, least significant bit first, where bit `p` of a record is\n * `(byte[p >> 3] >> (p & 7)) & 1`. `Bias` is -2 for a column containing NULLs: stored index 0\n * means NULL, and real symbols start at 2. This is exactly what the reader's\n * `decodeIndexColumn` undoes, and `writeBitField` is its inverse.\n *\n * The previous implementation went the long way round. Per cell it converted the raw value to\n * a QvdSymbol - a second time, the symbol table pass having already done it - to build a\n * template-literal lookup key, then turned the resulting index into a string of bits via\n * `toString(2).split('').map().reverse().concat().slice().reverse()`. Per row it kept an array\n * of those strings, padded each with `padStart`, reversed and joined them, split the result\n * with `/.{1,8}/g`, and allocated a Buffer; then `Buffer.concat` over one Buffer per row. On\n * the 1.7M-row taxi fixture that is 34 million symbols, 34 million key strings, 34 million bit\n * strings and 1.7 million Buffers, and it accounted for 98% of a write.\n *\n * Now: the widths are derived from the symbol counts, the offsets by prefix sum, one Buffer is\n * allocated for the whole table, and each value is OR-ed into place as an integer.\n *\n * @private\n */\n _buildIndexTable() {\n assert(this._symbolCounts, 'The QVD file symbol table has not been built.');\n assert(this._symbolTableMetadata, 'The QVD file symbol table metadata has not been built.');\n assert(this._symbolIndexByValue, 'The QVD file symbol index has not been built.');\n\n this._indexTableMetadata = [];\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numRows = data.length;\n const numColumns = columns.length;\n\n this._recordCount = numRows;\n this._emitProgress('index-table', 0, numRows);\n\n // Layout, one entry per column, hoisted out of the row loop so the inner loop does\n // arithmetic into a buffer and nothing else.\n /** @type {Array<{geometry: {byteStart: number, shift: number, byteCount: number}, nullShift: number}>} */\n const layout = [];\n\n let totalBits = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const fieldContainsNull = this._symbolTableMetadata[column][2];\n const symbolCount = this._symbolCounts[column];\n const nullShift = fieldContainsNull ? 2 : 0;\n\n // The largest stored index is (symbolCount - 1), shifted by 2 when the column contains\n // NULLs (index 0 denotes NULL and indices start at 2, which is what Bias=-2 encodes).\n //\n // Deriving the width this way is O(1) per column instead of O(rows), and it avoids\n // Math.max(...oneArgumentPerRow), which overflows the call stack somewhere around\n // 120k rows and made toQvd() unusable for realistic table sizes.\n const maxStoredIndex = symbolCount === 0 ? 0 : symbolCount - 1 + nullShift;\n\n // A single distinct value needs no bits at all, which matches what Qlik emits.\n const bitWidth = maxStoredIndex === 0 ? 0 : 32 - Math.clz32(maxStoredIndex);\n\n // Every index the row loop can write, checked once per column rather than once per cell.\n //\n // The row loop writes either 0, for NULL, or a value from these maps, so validating the\n // maps validates every write - 28,512 checks on the taxi fixture instead of 34 million,\n // and it covers the zero-width columns the per-cell check used to skip past. The bound is\n // the symbol count, not the field's capacity: a per-cell `storedIndex >= 2 ** bitWidth`\n // admitted indices in the gap between the two, which address no symbol. A reader before\n // #125 read them back without an error, and one after it refuses the file.\n const lookup = this._symbolIndexByValue[column];\n const maps = lookup.byCell === lookup.byKey ? [lookup.byKey, lookup.byObject] : Object.values(lookup);\n\n for (const map of maps) {\n for (const index of map.values()) {\n if (index + nullShift > maxStoredIndex) {\n throw new QvdValidationError('The symbol table and the index table are out of sync', {\n field: columns[column],\n storedIndex: index + nullShift,\n maxStoredIndex,\n symbolCount,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n }\n }\n\n layout.push({geometry: fieldGeometry(totalBits, bitWidth), nullShift});\n\n this._indexTableMetadata.push([totalBits, bitWidth, fieldContainsNull ? -2 : 0]);\n\n totalBits += bitWidth;\n }\n\n // Every column may have a bit width of 0 - each holds a single distinct value, or only\n // NULLs - leaving no bits at all. Qlik still uses a one-byte record in that situation, and\n // a zero-byte record would be rejected on read.\n const recordByteSize = Math.max(1, Math.ceil(totalBits / 8));\n\n this._recordByteSize = recordByteSize;\n this._indexBuffer = Buffer.alloc(numRows * recordByteSize);\n\n const progressInterval = Math.max(1, Math.floor(numRows / 100)); // Report progress every 1%\n\n // Hoisted, as in the symbol table pass, so a cell costs one array read and one lookup.\n const byCells = this._symbolIndexByValue.map((lookup) => lookup.byCell);\n const byKeys = this._symbolIndexByValue.map((lookup) => lookup.byKey);\n const byObjects = this._symbolIndexByValue.map((lookup) => lookup.byObject);\n\n for (let row = 0, recordBase = 0; row < numRows; row++, recordBase += recordByteSize) {\n const values = data[row];\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n // NULL is stored index 0, which the bias turns back into a negative index on read.\n // Nothing to write: the buffer is already zeroed.\n continue;\n }\n\n // A dual object is remembered by identity up to a bound, and past it found by its number, which\n // the symbol table pass has already checked for this same object.\n const index =\n typeof value === 'object'\n ? (byObjects[column].get(value) ?? byKeys[column].get(value.number))\n : byCells[column].get(value);\n\n // A value the symbol table never saw. Unreachable while both passes walk the same rows,\n // which is the point of them sharing a counted loop - but the old code absorbed this\n // with `?? 0`, writing the first real symbol in place of the missing value, so a whole\n // column could read back as some other value with nothing thrown.\n if (index === undefined) {\n throw new QvdValidationError('A value is missing from the symbol table', {\n field: columns[column],\n row,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n\n writeBitField(this._indexBuffer, recordBase, layout[column].geometry, index + layout[column].nullShift);\n }\n\n // Report progress periodically\n if ((row + 1) % progressInterval === 0 || row + 1 === numRows) {\n this._emitProgress('index-table', row + 1, numRows);\n }\n }\n\n // The maps are dead once the table is packed, and the writer stays alive through the header\n // build and the file write - the point at which the symbol buffer and the index buffer are\n // both resident.\n this._symbolIndexByValue = null;\n }\n\n /**\n * Persists the data frame to a QVD file.\n */\n async save() {\n this._buildSymbolTable();\n this._buildIndexTable();\n this._buildHeader();\n await this._writeData();\n }\n}\n","// @ts-check\n\nimport os from 'os';\nimport v8 from 'v8';\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Gets the configured V8 heap size limit for the current Node.js process.\n * This respects the --max-old-space-size flag if set.\n *\n * @returns {number} Heap size limit in bytes\n */\nexport function getHeapLimit() {\n return v8.getHeapStatistics().heap_size_limit;\n}\n\n/**\n * Whether v8.getHeapStatistics().heap_size_limit means what it says on this runtime.\n *\n * Bun reports its *current* heap there rather than a ceiling - 229MB on a machine with 128GB of\n * RAM - so treating it as a limit rejects almost everything. It cannot be detected structurally\n * either: Bun spoofs both process.versions.v8 and process.versions.node, so the runtime's own\n * key is the only reliable signal.\n *\n * @return {boolean} True when the heap limit is a real limit.\n */\nfunction heapLimitIsMeaningful() {\n return !process.versions.bun && !process.versions.deno;\n}\n\n/**\n * Works out how much memory this process may actually use, and which limit decided it.\n *\n * Only two things can bind, and the smaller wins:\n *\n * - The V8 heap ceiling, which is what an allocation actually fails against, fatally and\n * uncatchably. V8 sizes it from physical memory by default, so it already scales down on a\n * small machine.\n * - A container memory limit, from process.constrainedMemory(). This is the case os.freemem()\n * gets dangerously wrong: inside a cgroup it reports the *host's* free memory, so a 2GB\n * container on a large host sails past the check and is then killed by the OOM killer with\n * exit 137 and no JavaScript error to catch.\n *\n * What the OS reports as free or available is deliberately *not* one of them. It is recorded for\n * diagnostics and ignored for the decision, because it does not describe a wall the process can\n * hit - a machine with virtual memory gets slower, not fatal - and because the number itself is\n * not trustworthy. os.freemem() counts only free and speculative pages, excluding the inactive\n * and file-cache pages the OS reclaims on demand. process.availableMemory() is meant to fix that\n * and does on Linux, but on macOS it depends on the libuv version underneath: Node 24 reported\n * 63GB on a 128GB machine here while Node 22 on a macOS CI runner reported 74MB, which refused a\n * 45MB load on a machine that had ample room for it. Letting either bind is what made the same\n * file load or fail from one minute, or one Node version, to the next.\n *\n * @return {{bytes: number, limitedBy: string, candidates: Array<{source: string, bytes: number}>,\n * observed: Array<{source: string, bytes: number}>}} The budget, the name of the limit that\n * bound it, what was allowed to bind, and what was recorded but not used.\n */\nexport function getMemoryBudget() {\n /** @type {Array<{source: string, bytes: number}>} */\n const candidates = [];\n\n if (heapLimitIsMeaningful()) {\n candidates.push({source: 'V8 heap limit', bytes: usableOldSpaceLimit()});\n }\n\n // Node returns 0 when the process is not constrained. Bun returns os.totalmem() instead, which\n // is not a constraint either, so anything at or above total memory is discarded rather than\n // treated as a container limit.\n const constrained = typeof process.constrainedMemory === 'function' ? process.constrainedMemory() : 0;\n if (constrained > 0 && constrained < os.totalmem()) {\n candidates.push({source: 'container memory limit', bytes: constrained});\n }\n\n // Bun outside a container has neither a usable heap limit nor a container limit, so without\n // this there would be no ceiling at all. Total memory is at least a real upper bound.\n if (candidates.length === 0) {\n candidates.push({source: 'total system memory', bytes: os.totalmem()});\n }\n\n /** @type {Array<{source: string, bytes: number}>} */\n const observed = [{source: 'free memory (os.freemem)', bytes: os.freemem()}];\n if (typeof process.availableMemory === 'function') {\n observed.push({source: 'available memory', bytes: process.availableMemory()});\n }\n\n const binding = candidates.reduce((lowest, candidate) => (candidate.bytes < lowest.bytes ? candidate : lowest));\n\n return {bytes: binding.bytes, limitedBy: binding.source, candidates, observed};\n}\n\n/**\n * What `heap_size_limit` overstates the usable old-space limit by, in bytes.\n *\n * `v8.getHeapStatistics().heap_size_limit` counts new space, code space and the trusted spaces\n * as well as old space, and it is old space that a row-materialising load exhausts. Measured on\n * this platform the gap is a flat 192MB at every configured size - `--max-old-space-size=96`\n * reports 288, 512 reports 704, 2048 reports 2240 - so it is an absolute offset, not a\n * proportion, and a safety factor cannot express it. At a 4GB heap it is under 5% and a factor\n * absorbs it; at a heap configured down to a couple of hundred megabytes it is most of the\n * budget, which is where an under-sized estimate turned into a crash.\n *\n * It used to be absorbed into the per-row constants instead, which made those constants\n * describe two unrelated things at once and left them four to six times larger than the memory\n * they were supposed to model. Subtracting it here lets the row model be a row model.\n *\n * V8 exposes no per-space limit - `getHeapSpaceStatistics()` reports current sizes, not\n * ceilings - so this is an observed constant rather than a derived one. If it is wrong on some\n * platform it is wrong in the safe direction on a large heap, and the safety factor still\n * applies underneath.\n */\nconst HEAP_LIMIT_OVERSTATEMENT_BYTES = 192 * 1024 * 1024;\n\n/**\n * Smallest budget worth reporting, in bytes.\n *\n * This is a damage limiter for a platform where the 192MB offset does not hold, not a\n * description of a real ceiling. Subtracting an offset that does not apply would leave a budget\n * near zero and refuse everything, so the floor catches that.\n *\n * It has to leave room for `BASE_BYTES` plus a small load *after* the safety factor, or it\n * achieves the opposite of its purpose. An earlier value of 16MB was exactly `BASE_BYTES`, so at\n * the floor the estimate always exceeded the budget and even `misc/small.qvd` - 606 rows, 29KB -\n * was refused on a runtime where it demonstrably loads. 64MB clears `BASE_BYTES` four times\n * over.\n *\n * It over-claims only where the true old-space limit is under 64MB, which is not a configuration\n * this library can serve: the fixed cost of reading any file at all is 15MB of that.\n */\nconst MINIMUM_BUDGET_BYTES = 64 * 1024 * 1024;\n\n/**\n * The heap limit, less the spaces a row load cannot use.\n *\n * A plain subtraction, because the overstatement is a flat offset at every configured size:\n * `--max-old-space-size=47` reports 239, 96 reports 288, 4096 reports 4288. An earlier version\n * of this only subtracted when the reported limit exceeded twice the offset and otherwise\n * returned half of it, which was meant to avoid a non-positive result. It instead produced the\n * wrong answer across the whole range the correction exists for: at a 47MB heap it returned\n * 119MB, so the guard admitted a load that needed 63MB and the process aborted - the exact\n * failure this function is here to prevent, reintroduced by the fallback rather than by the\n * rule.\n *\n * @return {number} Usable bytes.\n */\nfunction usableOldSpaceLimit() {\n const usable = getHeapLimit() - HEAP_LIMIT_OVERSTATEMENT_BYTES;\n\n return usable > MINIMUM_BUDGET_BYTES ? usable : MINIMUM_BUDGET_BYTES;\n}\n\n/**\n * Estimates the memory usage for loading a QVD file with given parameters.\n * Takes into account Phase 2.5 optimization which skips parsing unused symbols.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Rows the read covers (null = all rows). Decides how much of the\n * symbol table is parsed.\n * @param {number} totalRows Total number of rows in the file\n * @param {number} [columnCount] Columns per row.\n * @param {boolean} [materialisesRows] Whether rows are built at all.\n * @param {number|null} [rowsLive] Rows held at one instant, when that is fewer than `maxRows`.\n * Null means they are the same. Note that this is what the *caller* holds, not its chunk size:\n * `iterateRows` passes two chunks, because `for await` keeps the yielded frame reachable while\n * the generator builds the next one.\n * @returns {number} Estimated memory usage in bytes\n */\n/**\n * What a row-materialising load costs, in bytes.\n *\n * `BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columns)`.\n *\n * Recalibrated 2026-09-11, after the bitwise decode (#134) stopped the reader allocating an\n * array per row and several per cell. The method is the one the original calibration used:\n * generate N rows x C columns where every value is `(i + j) % 100`, so the symbol table stays\n * negligible and only row geometry moves, then binary-search the smallest\n * `--max-old-space-size` at which the load completes.\n *\n * shape cells was (pre-#134) now model\n * 400,000 x 10 4M 118 MB 63 77\n * 800,000 x 5 4M 237 MB 87 106\n * 200,000 x 40 8M 142 MB 79 62\n * 400,000 x 40 16M 307 MB 151 109\n * 800,000 x 20 16M 484 MB 175 202\n * 1,600,000 x 10 16M 520 MB 215 259\n *\n * and against two real files, which the original calibration did not cover:\n *\n * lego/inventory_parts 580,251 x 5 63 MB 81\n * chicago_taxi_rides 2016_01 1,705,805 x 20 367 MB 412\n *\n * The reader needs roughly 2.4x less heap than it did, which is why the old constants - 360 and\n * 34 - over-estimated a taxi read by 4.8x and refused loads that fit comfortably.\n *\n * Two of the model's figures sit *below* the measurement (200,000 x 40 and 400,000 x 40). That\n * is not an under-estimate of the rows: those two shapes are dominated by the fixed cost of\n * reading a file at all, which `BASE_BYTES` covers and which the per-row terms should not be\n * inflated to absorb. Every shape's total prediction is above its measured minimum.\n *\n * The constants are what the geometry implies rather than fitted numbers: a row is a JSArray\n * with a separate backing store, so it costs two object headers plus slack, and a cell is one\n * pointer. Fitting the eight measurements above gives 55-64 and 7.1-7.3; 72 and 8 clear every\n * one of them by 13-26%, which is the margin. Under-estimating means an uncatchable abort,\n * over-estimating means a catchable refusal, so the margin is deliberately one-sided.\n *\n * `BASE_BYTES` is what a load costs before any rows exist - the interpreter, the parsed header,\n * the decoded index columns. Measured as the floor of the binary search: a columnar read of any\n * of these files, which builds no rows at all, completes at 15MB.\n */\nconst BASE_BYTES = 16 * 1024 * 1024;\nconst ROW_BASE_BYTES = 72;\nconst PER_CELL_BYTES = 8;\n\n/**\n * Bytes a read allocates *outside* the V8 heap, in bytes.\n *\n * The decoder builds one `Int32Array` of stored indices per field, and a TypedArray's backing\n * store is external memory: it does not consume old space, so `--max-old-space-size` does not\n * bound it and the V8 heap budget must not be charged for it. A columnar read of the 38MB taxi\n * fixture completes in a 15MB heap for exactly this reason.\n *\n * A cgroup counts it, though, and exceeding a container limit is a SIGKILL - uncatchable, and\n * strictly worse than the heap abort this module exists to prevent. So it is estimated, and\n * checked against the container budget rather than the heap one.\n *\n * Both paths allocate it. A row read builds the codes and then the rows from them, so during\n * the load both are live; a columnar read keeps only the codes. The file buffer is external\n * too, but its size is not known here, and the codes dominate on the shapes that get close to\n * a limit.\n *\n * @param {number} rows Rows that will be decoded.\n * @param {number} columnCount Columns per row.\n * @return {number} Estimated external bytes.\n */\nexport function estimateExternalMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0 || !rows || rows <= 0) {\n return 0;\n }\n\n return rows * columnCount * Int32Array.BYTES_PER_ELEMENT;\n}\n\n/**\n * Estimates the heap a row-materialising load will need, in bytes.\n *\n * @param {number} rows Rows that will be materialised.\n * @param {number} columnCount Columns per row. Zero disables the term, for callers that do not\n * know the geometry yet.\n * @return {number} Estimated bytes.\n */\nfunction estimateRowMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0) {\n return 0;\n }\n return BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columnCount);\n}\n\nexport function estimateMemoryUsage(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount = 0,\n materialisesRows = true,\n rowsLive = null,\n wholeSymbols = false,\n) {\n // Memory overhead multipliers based on empirical testing\n const FULL_PARSE_OVERHEAD = 6.0; // Baseline: JavaScript objects have 6x overhead\n const MINIMAL_OVERHEAD = 0.01; // Skipped symbols: minimal null placeholder overhead\n\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n\n // Two different row counts, because two different things are being sized.\n //\n // `maxRows` is how many rows the read *covers*, and it is what decides how much of the symbol\n // table gets parsed - chunked iteration parses the symbol table once for the whole window, not\n // once per chunk. `rowsLive` is how many rows are materialised at the same instant, which is\n // what the heap actually has to hold: for a plain read they are the same number, and for\n // `iterate({chunkSize})` the second is *two* chunks of the first - `for await` keeps the\n // yielded frame reachable while the generator builds the next one, so two are alive at the\n // peak. Measured, because charging one chunk admitted a read that then aborted the process;\n // the caller computes the figure and passes it, this function only uses it.\n //\n // Conflating them is the failure this module has made before in the other direction - charging\n // a columnar read for rows it never builds. Charging a 20-million-row iteration for all 20\n // million rows when only `chunkSize` of them exist at once is the same mistake, and it would\n // refuse the one call shape that exists to make such a file readable at all.\n const liveRows = rowsLive === null ? rowsToLoad : Math.min(rowsLive, rowsToLoad);\n\n // The rows themselves. This term used to be missing entirely, which is what made the guard\n // useless for the commonest Qlik shape: many rows over low-cardinality fields. A 150MB file\n // with a 0.43MB symbol table was estimated at 2.6MB and then killed a default heap.\n //\n // A columnar read materialises none of them, and what it does allocate - one Int32Array of\n // codes per field - is a TypedArray backing store, which lives outside the V8 heap this\n // budget describes. That is not a modelling nicety: binary-searching the smallest\n // --max-old-space-size at which a columnar read completes gives 15MB for every file tried,\n // from a 4MB fixture to the 38MB taxi one, because almost nothing it allocates is on the\n // heap. Charging it the row cost refused columnar reads that need a fortieth of the budget.\n const rowMemory = materialisesRows ? estimateRowMemory(liveRows, columnCount) : BASE_BYTES;\n\n if (maxRows === null || maxRows >= totalRows || wholeSymbols) {\n // Loading all rows - need all symbols, no filtering benefit.\n //\n // `wholeSymbols` says the same thing for a read that covers a window: the discount below models the\n // two-pass path, where a symbol no row of the window uses is walked past without being decoded. A\n // paging read turns that path off, because a column decoded for one page is kept for the next and a\n // column decoded in part would answer `undefined` for a row a later page asks about. So it holds\n // every symbol of every column it has touched, and charging it a square root of them was an\n // under-estimate - the direction that ends in a heap-limit abort rather than an error.\n return symbolTableSize * FULL_PARSE_OVERHEAD + rowMemory;\n }\n\n // Estimate what percentage of symbols we'll need\n // Symbol usage grows slower than linear (diminishing returns as you add rows)\n // Use square root scaling as empirical approximation\n const rowPercentage = maxRows / totalRows;\n const symbolPercentage = Math.sqrt(rowPercentage);\n\n // Calculate memory for kept symbols (full overhead) + skipped symbols (minimal overhead)\n const keptSymbolsMemory = symbolTableSize * symbolPercentage * FULL_PARSE_OVERHEAD;\n const skippedSymbolsMemory = symbolTableSize * (1 - symbolPercentage) * MINIMAL_OVERHEAD;\n\n return keptSymbolsMemory + skippedSymbolsMemory + rowMemory;\n}\n\n/**\n * Finds the largest row count whose estimate fits inside a budget.\n *\n * The estimate is monotonic in rows but not invertible in closed form - the symbol term scales\n * with sqrt(rows/totalRows) while the row term scales linearly - so this bisects instead, and\n * the answer is therefore a value the caller can actually use. The previous implementation\n * inverted the square-root term alone and suggested row counts that the same check rejected on\n * the next call.\n *\n * When the limit that refused the read bounds the whole process rather than the V8 heap, the\n * external term has to be counted here too. Without it the suggestion is bisected against a\n * different quantity from the one the refusal used - and for a columnar read, whose heap estimate\n * barely moves with rows, the first test succeeds and it hands back the exact row count it just\n * refused. Recommending the input that produced the error is worse than recommending nothing.\n *\n * @param {number} budget Bytes available.\n * @param {number} symbolTableSize Size of the symbol table in bytes.\n * @param {number} totalRows Rows the file declares.\n * @param {number} columnCount Columns per row.\n * @param {boolean} [materialisesRows=true] Whether rows are built at all.\n * @param {boolean} [includeExternal=false] Count TypedArray backing stores, for a limit that\n * bounds the process rather than old space.\n * @return {number} A row count whose estimate fits the budget, or 0 when none does.\n */\nexport function recommendedRowsFor(\n budget,\n symbolTableSize,\n totalRows,\n columnCount,\n materialisesRows = true,\n includeExternal = false,\n wholeSymbols = false,\n) {\n const costOf = (/** @type {number} */ rows) =>\n estimateMemoryUsage(symbolTableSize, rows, totalRows, columnCount, materialisesRows, null, wholeSymbols) +\n (includeExternal ? estimateExternalMemory(Math.min(rows, totalRows), columnCount) : 0);\n\n if (costOf(totalRows) <= budget) {\n return totalRows;\n }\n\n // The bisection below treats `low` as a value known to fit, so that has to be true of its\n // starting point. It is not automatic: the estimate charges 1% of the symbol table even when\n // no rows are requested, so a symbol table two orders of magnitude larger than the budget\n // leaves nothing that fits. Clamping the answer up to 1 in that case produced a suggestion\n // the caller could not use - `maxRows: 1` threw the same error it had just been offered as\n // the fix for.\n if (costOf(0) > budget) {\n return 0;\n }\n\n let low = 0;\n let high = totalRows;\n while (high - low > 1) {\n const mid = Math.floor((low + high) / 2);\n if (costOf(mid) <= budget) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Finds the largest chunk size whose estimate fits inside a budget.\n *\n * The sibling of `recommendedRowsFor`, for the one caller whose knob is not the window. Chunked\n * iteration parses the symbol table once for the whole window however small the chunks are, so\n * the window is held fixed here and only the live-row term moves - bisecting the window instead\n * would recommend a number that does not correspond to anything the caller can set.\n *\n * The answer is in the caller's units, which is why `liveRowsPerChunk` has to be given rather\n * than assumed to be one: the iterator holds two chunks at a time, so bisecting live rows and\n * calling the result a chunk size would recommend a chunk twice as large as fits - and the caller\n * would be refused again on the very next call, which is the loop this function exists to avoid.\n *\n * @param {number} budget Bytes available.\n * @param {number} symbolTableSize Size of the symbol table in bytes.\n * @param {number|null} windowRows Rows the iteration covers, which fixes the symbol term.\n * @param {number} totalRows Rows the file declares.\n * @param {number} columnCount Columns per row.\n * @param {number} [liveRowsPerChunk=1] Rows alive per row of chunk size.\n * @param {boolean} [includeExternal=false] Count TypedArray backing stores, for a limit that\n * bounds the process rather than old space - see `recommendedRowsFor`.\n * @param {boolean} [wholeSymbols=false] Whether the read holds every symbol of the columns it touches\n * rather than only those its window uses - true for a paging read. It has to reach here as well as\n * the answer: advice priced with the discount that the answer refused without it is advice the very\n * next call rejects.\n * @return {number} A chunk size whose estimate fits the budget, or 0 when none does.\n */\nexport function recommendedChunkFor(\n budget,\n symbolTableSize,\n windowRows,\n totalRows,\n columnCount,\n liveRowsPerChunk = 1,\n includeExternal = false,\n wholeSymbols = false,\n) {\n const covered = windowRows === null || windowRows >= totalRows ? totalRows : windowRows;\n\n const fits = (/** @type {number} */ chunk) => {\n const live = Math.min(chunk * liveRowsPerChunk, covered);\n const cost =\n estimateMemoryUsage(\n symbolTableSize,\n windowRows,\n totalRows,\n columnCount,\n true,\n chunk * liveRowsPerChunk,\n wholeSymbols,\n ) + (includeExternal ? estimateExternalMemory(live, columnCount) : 0);\n\n return cost <= budget;\n };\n\n if (fits(covered)) {\n return covered;\n }\n\n // A chunk of one row is the smallest thing a caller can ask for. If even that does not fit,\n // the symbol table alone has exhausted the budget and no chunk size helps - say so rather than\n // returning a number the very next call rejects.\n if (!fits(1)) {\n return 0;\n }\n\n let low = 1;\n let high = covered;\n while (high - low > 1) {\n const mid = Math.floor((low + high) / 2);\n if (fits(mid)) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * A read that holds no bytes of the file, for a caller that declares none.\n *\n * One shape rather than two, so every use of the charge below is a field access. It used to accept a\n * plain number as well, which every use then had to branch on, and which let a test give one function\n * for both knobs and so prove nothing about which of them priced an answer.\n */\nconst noBytesHeld = Object.freeze({held: 0, forRows: () => 0, forChunk: () => 0});\n\n/**\n * Validates that there is sufficient memory available to load a QVD file safely.\n * Considers both available system RAM and the configured V8 heap limit.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} [safetyFactor=0.8] Fraction of the memory budget to use (0.0-1.0). Zero\n * disables the check entirely.\n *\n * The default was 0.3 while the estimate counted only the symbol table - a proxy that\n * understated real cost by around a hundredfold for the commonest Qlik shape, so the factor was\n * quietly compensating for it. Now that the estimate models the rows too, 0.3 would double-count\n * that margin and refuse loads with four times the headroom they need. The estimate sits about\n * 1.2-1.6x above the measured requirement, so 0.8 still leaves V8 room to collect.\n * @param {number} [columnCount=0] Columns per row, so the estimate can account for the row\n * arrays. Zero omits that term, which is what the old symbol-table-only estimate did.\n * @param {boolean} [materialisesRows=true] Whether this read builds row arrays at all.\n * @param {{rows: number, perChunk: number}|null} [live=null] For a read that holds fewer rows at\n * once than it covers: `rows` is how many are alive at the peak, and `perChunk` how many of\n * those one row of the caller's chunk size accounts for, so a refusal can name a chunk size.\n * Null means the read holds everything it covers, which is every read but chunked iteration.\n * @param {{held: number, forRows: (rows: number) => number, forChunk: (rows: number) => number}|null}\n * [bytesHeld=null] Bytes of file the read holds outside the heap while it works: the symbol areas it\n * reads, and the one buffer its records come through. Counted with the codes, against a limit that\n * bounds the process rather than old space. `held` is this read's; `forRows` and `forChunk` say what a\n * read of so many rows, or of so many rows a chunk, would hold instead, so that each suggestion is\n * priced at its own record buffer rather than at this read's or at the other suggestion's. `null` and\n * `undefined` both mean a read that holds nothing of the file.\n * @param {number|null} [readBytes=null] Bytes the read will read from the file, carried into the\n * answer so that a refusal's `check` says everything a pre-flight would have said.\n * @throws {QvdValidationError} If insufficient memory is available\n */\nexport function validateMemoryAvailability(\n symbolTableSize,\n maxRows,\n totalRows,\n filePath,\n safetyFactor = 0.8,\n columnCount = 0,\n materialisesRows = true,\n live = null,\n bytesHeld = null,\n readBytes = null,\n wholeSymbols = false,\n retainedBytes = 0,\n) {\n const answer = checkMemory({\n wholeSymbols,\n retainedBytes,\n symbolTableSize,\n maxRows,\n totalRows,\n safetyFactor,\n columnCount,\n materialisesRows,\n live,\n bytesHeld,\n readBytes,\n });\n\n if (answer.fits) {\n return;\n }\n\n const {message, context} = answer.refusal;\n\n // The same message and the same context keys this has always thrown, so a caller matching on\n // either is unaffected - with `reason` and `check` added beside them. `check` is the whole answer\n // a pre-flight would have given for this read, so a caller that did not ask beforehand gets it\n // from the refusal rather than having to ask again.\n throw new QvdValidationError(message, {\n file: filePath,\n ...context,\n reason: 'memory',\n check: answerOf(answer),\n });\n}\n\n/**\n * What a read would cost, and whether it fits, without refusing it.\n *\n * The same computation the refusal is built from - deliberately the same, because a pre-flight that\n * answered a different question from the one the read asks is worse than no pre-flight at all. A read\n * this approves is not refused later for memory, and every suggestion it offers has been read back\n * through it.\n *\n * @param {object} params What the read will do.\n * @param {number} params.symbolTableSize Bytes of symbols the read will read - the areas of the fields\n * it selects, not the table they sit in.\n * @param {number|null} params.maxRows Rows the window covers, or null for every row.\n * @param {number} params.totalRows Rows the file declares.\n * @param {number} [params.safetyFactor=0.8] Fraction of the budget the read may use. Zero disables the\n * check, and makes this answer `fits` with no estimate to stand behind it.\n * @param {number} [params.columnCount=0] Columns the read builds.\n * @param {boolean} [params.materialisesRows=true] Whether it builds row arrays at all.\n * @param {{rows: number, perChunk: number}|null} [params.live=null] Rows held at one instant when that\n * is fewer than the window covers - chunked iteration, and nothing else.\n * @param {{held: number, forRows: (rows: number) => number, forChunk: (rows: number) => number}|null}\n * [params.bytesHeld=null] Bytes of the file the read holds outside the heap - see\n * `validateMemoryAvailability`.\n * @param {number|null} [params.readBytes=null] Bytes it will read from the file, for the answer's\n * estimate. It does not enter the decision: reading is not holding.\n * @param {boolean} [params.wholeSymbols=false] Whether the read decodes every symbol of the columns it\n * touches rather than only those its window uses - true for a paging read, which keeps what it\n * decodes and so cannot decode a column in part.\n * @param {number} [params.retainedBytes=0] Of `symbolTableSize`, the bytes belonging to columns an\n * earlier read decoded and kept that this one does not select - what letting go of the file would\n * release without changing what this read needs. It decides whether a refusal is the cache's fault,\n * which `wholeSymbols` cannot: that is true from the moment paging is switched on, before any page\n * has decoded anything.\n * @param {any} [params.measured=null] A budget already measured by `getMemoryBudget`, for a caller\n * asking several questions at once. Sizing a suggestion means asking again, and asking again\n * re-measured the budget each time - so a suggestion was checked against a slightly different budget\n * from the answer that prompted it, and a wide file paid for a `v8.getHeapStatistics()` call per\n * column. Passing one in makes the whole set of questions one measurement.\n * @return {{fits: boolean, reason?: string, estimate: {heapBytes: number, externalBytes: number,\n * readBytes: number|null}, budget: {heapBytes: number, processBytes: number|null, bound: string,\n * safetyFactor: number, allowedBytes: number, candidates: Array<{source: string, bytes: number}>,\n * observed: Array<{source: string, bytes: number}>}, exact: boolean,\n * suggestions: Array<{option?: string, nodeOption?: string, value: any}>,\n * refusal?: {message: string, context: object}}} The answer.\n */\nexport function checkMemory({\n symbolTableSize,\n maxRows,\n totalRows,\n safetyFactor = 0.8,\n columnCount = 0,\n materialisesRows = true,\n live = null,\n bytesHeld = null,\n readBytes = null,\n measured = null,\n wholeSymbols = false,\n retainedBytes = 0,\n}) {\n if (typeof safetyFactor !== 'number' || safetyFactor < 0 || safetyFactor > 1) {\n throw new QvdValidationError('safetyFactor must be a number between 0.0 and 1.0', {\n safetyFactor,\n reason: 'option',\n option: 'memorySafetyFactor',\n value: safetyFactor,\n });\n }\n\n // Zero disables the check. It used to mean a budget of zero bytes, which refused every file\n // however small - not something any caller can have wanted - so the only reading that makes it\n // useful is \"I will manage memory myself\". This is the documented escape hatch for runtimes\n // whose limits cannot be measured, and for callers who know better than the estimate.\n //\n // It fits by definition rather than by measurement, and the answer says so through `safetyFactor: 0`\n // and an `allowedBytes` of Infinity - not by reporting a cost of nothing. What a read would cost does\n // not depend on whether anything is enforcing a limit, and the estimate is arithmetic on the header\n // rather than a measurement, so it is as good here as anywhere. Returning zeros made the pre-flight\n // answer \"it costs nothing\" for every read by a caller who had turned enforcement off, which is the\n // one question it exists to answer. What is skipped below is the decision, not the estimate.\n const budget = measured ?? getMemoryBudget();\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n\n // `live` describes a read that holds fewer rows at once than it covers - chunked iteration, and\n // nothing else so far. `rows` is how many are alive at the peak; `perChunk` is how many of them\n // one row of the caller's chunk size buys, so that a refusal can recommend a chunk size rather\n // than a live-row count. Both come from the same caller in the same call, so they cannot\n // describe different reads.\n const rowsLive = live === null ? null : live.rows;\n const liveRowsPerChunk = live === null ? 1 : live.perChunk;\n\n // The codes are allocated for whatever is decoded at once, which is one chunk under chunked\n // iteration and the whole window otherwise - the same distinction the heap estimate draws, and\n // it has to be drawn in both places or the two halves of the check describe different reads.\n const liveRows = rowsLive === null ? rowsToLoad : Math.min(rowsLive, rowsToLoad);\n const heapMemory = estimateMemoryUsage(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount,\n materialisesRows,\n rowsLive,\n wholeSymbols,\n );\n\n // The codes, and the bytes the read holds while it parses them: the symbol areas it reads and the one\n // buffer its records come through. All three are TypedArray or Buffer storage, which does not occupy old\n // space but does count against a container, so they are charged where the codes are.\n //\n // `held` is what this read holds; `forRows` and `forChunk` say what a read following either piece of\n // advice would hold instead, which is what the suggestions below need. The symbol areas do not move with\n // the row count, but the record buffer does, shrinking with the rows until it is one slice no longer, so\n // a suggestion priced at this read's buffer is one the next call refuses.\n //\n // Two functions, because the two knobs move different things. A smaller `limit` is a smaller window;\n // a smaller `chunkSize` is the same window decoded in smaller pieces. `forRows` and `forChunk` are that\n // distinction, and using one where the other belongs is how the chunk advice came to be priced at a read\n // that does not exist.\n //\n // `noBytesHeld` covers a caller that says nothing - `null` as much as `undefined`, since a default fires\n // only for the second and an argument list of nulls is how a caller says \"nothing to declare\" here.\n const {\n held,\n afterRelease: heldAfterRelease = null,\n forRows: heldForRows,\n forChunk: heldForChunk,\n } = bytesHeld ?? noBytesHeld;\n const externalMemory = estimateExternalMemory(liveRows, columnCount) + held;\n\n // Each candidate is measured against the memory it actually bounds. The V8 heap limit bounds\n // old space, which TypedArray backing stores do not occupy; a container limit bounds the\n // process, which they do. Checking one figure against both was wrong in both directions at\n // once: it refused columnar reads that fit the heap forty times over, and - once that was\n // fixed by not charging them for rows - it admitted a columnar read allocating 130MB of codes\n // inside a container with less than that, where the kernel answers with a SIGKILL.\n const bounded = budget.candidates.map((candidate) => {\n const heapOnly = candidate.source === 'V8 heap limit';\n\n return {\n ...candidate,\n heapOnly,\n needs: heapOnly ? heapMemory : heapMemory + externalMemory,\n allowed: candidate.bytes * safetyFactor,\n bounds: heapOnly ? 'the V8 heap' : 'the whole process',\n };\n });\n\n // The candidate closest to binding, whether or not it binds. One rule for both branches, because\n // `bound` and `allowedBytes` describe the same candidate either way: on a refusal it is the one that\n // refused, and on an answer that fits it is the one with the least room left. They used to be worked\n // out two different ways - the worst ratio when refusing, the smallest allowance when fitting - so the\n // same two fields meant different things depending on the answer, and a caller could not compare the\n // estimate against the allowance without knowing which branch had produced it.\n if (safetyFactor === 0) {\n const lowest = budget.candidates.reduce((least, candidate) => (candidate.bytes < least.bytes ? candidate : least));\n\n return {\n fits: true,\n estimate: {heapBytes: heapMemory, externalBytes: externalMemory, readBytes},\n // The ceilings are still there and still named - what is missing is any measurement against them.\n // An earlier version reported `bound: 'none'` here, a third value in a two-value vocabulary that a\n // caller switching on the documented two would fall straight through.\n budget: {\n ...budgetOf(budget, {...lowest, heapOnly: lowest.source === 'V8 heap limit'}, 0),\n allowedBytes: Infinity,\n },\n exact: symbolTableSize === 0,\n suggestions: [],\n };\n }\n\n const tightest = bounded.reduce((worst, candidate) =>\n candidate.needs / candidate.allowed > worst.needs / worst.allowed ? candidate : worst,\n );\n const binding = tightest.needs > tightest.allowed ? tightest : null;\n\n const heapLimit = getHeapLimit();\n const availableMemory = binding ? binding.bytes : budget.bytes;\n const estimatedMemory = binding ? binding.needs : heapMemory;\n const maxAllowedMemory = binding ? binding.allowed : budget.bytes * safetyFactor;\n\n // Whether the columns an earlier read left behind are what refused this one - which is a different\n // question from whether paging is on. `wholeSymbols` is true from `beginPaging()` onwards, so\n // branching on it told a first page, and a `check()` made before any page, that previously decoded\n // columns were to blame and that closing the file would release them. Nothing was held, closing\n // released nothing, and the retry failed identically.\n //\n // The honest test is counterfactual: take the retained columns out of the estimate and see whether\n // what is left fits. Only then is letting go of them a remedy rather than a distraction.\n const retainedIsTheReason = (() => {\n if (binding === null || retainedBytes <= 0) {\n return false;\n }\n\n const heapAfter = estimateMemoryUsage(\n Math.max(0, symbolTableSize - retainedBytes),\n maxRows,\n totalRows,\n columnCount,\n materialisesRows,\n rowsLive,\n wholeSymbols,\n );\n // Not `externalMemory - retainedBytes`: the retained columns were never in it. `bytesHeld` is built\n // from the areas this read still has to read, which excludes anything cached, so subtracting them\n // removed bytes nobody had charged and made releasing look like a cure more often than it is.\n // `afterRelease` is the honest figure, and it is the larger one.\n const externalAfter = estimateExternalMemory(liveRows, columnCount) + (heldAfterRelease ?? held);\n\n // Every candidate, not just the one binding now. Releasing heap-held columns can leave a different\n // ceiling binding - a container limit that the external bytes of rereading them reach - and telling\n // a caller to reopen when the reopened read is refused by something else is the same wrong advice\n // one step along.\n return budget.candidates.every((candidate) => {\n const heapOnly = candidate.source === 'V8 heap limit';\n\n return (heapOnly ? heapAfter : heapAfter + externalAfter) <= candidate.bytes * safetyFactor;\n });\n })();\n\n if (binding) {\n // Bisected against the same estimate this check uses, so the suggestion is one the caller\n // can act on. It used to invert the square-root symbol term alone and could suggest a row\n // count that the very next call rejected.\n // Bisected against the same quantity the refusal compared, which for a process-bounded limit\n // includes the external term. A suggestion measured against a different budget from the\n // refusal is the same mismatch this module exists to avoid, one level up.\n const includeExternal = !binding.heapOnly;\n\n // The bytes of file come off the budget the suggestion is bisected against, rather than out of the\n // estimate, because the symbols do not move with the row count. The record buffer does: a read holding\n // fewer rows reads fewer records at a time, until it is one slice no longer. So the budget has to be\n // the one the suggestion itself would hold against, and one pass does not find it.\n //\n // `fitting` falls as its argument rises, since a larger read holds a larger buffer and leaves less of\n // the budget for rows. A row count is therefore one the next call accepts exactly when\n // `rows <= fitting(rows)`, and applying `fitting` alternates about that line: `firstGuess`, priced at\n // this read's charge, satisfies it; `over` is the larger answer that smaller charge allows, and does\n // not; `under` is `over` priced at its own charge, and satisfies it again. The advice is the larger of\n // the two that hold, so it is both a row count that fits and no smaller than the cautious first pass.\n //\n // Bisected once against this read's charge alone, the answer could be \"no row count fits\" where a\n // smaller read fitted. Bisected twice, it overshot instead: 8MB of symbols, a 16MB slice and 64 bytes\n // a row in a 32MB container advised 4,449 rows, and 4,449 rows was refused by the very next call -\n // the loop this module exists to avoid, one level up.\n const rowsHeldBudget = (/** @type {number} */ rows) => maxAllowedMemory - (includeExternal ? heldForRows(rows) : 0);\n const fitting = (/** @type {number} */ rows) =>\n recommendedRowsFor(\n rowsHeldBudget(rows),\n symbolTableSize,\n totalRows,\n columnCount,\n materialisesRows,\n includeExternal,\n wholeSymbols,\n );\n const firstGuess = fitting(liveRows);\n const over = fitting(firstGuess);\n const under = fitting(over);\n const recommendedMaxRows = Math.max(firstGuess, under);\n\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const availableMB = Math.round(maxAllowedMemory / 1024 / 1024);\n // The usable figure, not the reported one. These differ by the 192MB of non-old-space\n // that heap_size_limit counts, and printing the reported one next to a budget breakdown\n // carrying the corrected one told the reader two different things about the same limit -\n // in the one diagnostic whose job is to say which knob to turn.\n const heapLimitMB = Math.round(usableOldSpaceLimit() / 1024 / 1024);\n const reportedHeapLimitMB = Math.round(heapLimit / 1024 / 1024);\n const availableRamMB = Math.round(availableMemory / 1024 / 1024);\n\n // Naming the limit that bound the decision is the difference between an actionable error and\n // a puzzling one: raising --max-old-space-size fixes a heap-bound refusal and does nothing\n // for a container-bound one, where it makes the OOM kill more likely rather than less.\n // The bare source name, because callers match it against memoryBudget[].source - a test\n // pins that. What the limit bounds goes in its own field and into the prose.\n const limitingFactor = binding.source;\n const limitingScope = binding.bounds;\n const budgetBreakdown = budget.candidates\n .map((candidate) => `${candidate.source} ${Math.round(candidate.bytes / 1024 / 1024)}MB`)\n .join(', ');\n const observedBreakdown = budget.observed\n .map((entry) => `${entry.source} ${Math.round(entry.bytes / 1024 / 1024)}MB`)\n .join(', ');\n\n // Saying \"try maxRows: N\" when no N fits sends the caller round a loop, so that case gets its\n // own advice rather than a number that will be rejected on the next call.\n //\n // A chunked read gets a different knob named, because the one it has is not the window. Its\n // window may be the whole file by design, and shrinking it is not what the caller wants to\n // hear when what actually overflowed is one chunk.\n //\n // It is bisected exactly as the row count above is, and for the same reason, but against its own\n // charge: `forChunk`, not `forRows`. A chunk is not a row count - `chunkSize` leaves the window where\n // it is - so pricing the advice at a row count's buffer was pricing it at a read that does not exist.\n // On 1MB of symbols, 40-byte records and two columns of a million rows in a 48MB container, that\n // advised a chunk of 74,730 rows and then refused it; across a sweep of 1,104 refusals that carried\n // chunk advice, 299 came back refused.\n const containerBound = binding.source === 'container memory limit';\n const chunked = rowsLive !== null;\n const chunkHeldBudget = (/** @type {number} */ rows) =>\n maxAllowedMemory - (includeExternal ? heldForChunk(rows) : 0);\n const chunkFitting = (/** @type {number} */ rows) =>\n recommendedChunkFor(\n chunkHeldBudget(rows),\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount,\n liveRowsPerChunk,\n includeExternal,\n wholeSymbols,\n );\n // The caller's own chunk is the starting point, as this read's row count was for the row advice.\n const callersChunk = chunked ? Math.max(1, Math.floor(rowsLive / Math.max(1, liveRowsPerChunk))) : 0;\n const firstChunk = chunked ? chunkFitting(callersChunk) : 0;\n const overChunk = chunked ? chunkFitting(firstChunk) : 0;\n const recommendedChunk = chunked ? Math.max(firstChunk, chunkFitting(overChunk)) : 0;\n const knob = chunked ? 'chunkSize' : 'limit';\n const recommendedValue = chunked ? recommendedChunk : recommendedMaxRows;\n const nothingFits = recommendedValue === 0;\n\n // What the fixed cost of this read actually is, which is not always the file's symbol table. A paging\n // read is charged for every column any of its pages has decoded and kept, so on a wide file the part\n // that does not fit is usually what the caller is still holding rather than anything about the file.\n // Saying \"the symbol table alone exceeds it\" there was untrue - 2MB of symbols against a 24MB budget,\n // with 28MB needed - and it named the one remedy that does not help, because raising the limit is not\n // what a caller who has paged across twenty columns should reach for first.\n const held = retainedIsTheReason;\n // The verb travels with the phrase, because one subject is plural and the other is not.\n const fixedCost = held ? 'the columns this file is holding exceed' : 'the symbol table alone exceeds';\n const release = held ? `Close the file and open it again to release them, or raise ` : `Raise `;\n\n // Named in every branch a cache-caused refusal can reach, not only the one where nothing fits. A\n // page can be refused with a smaller page still available *and* the columns being held still the\n // reason, and that caller was told to shrink the page or raise a limit without being told the one\n // thing that would give them the whole page back. Direct remedy first, fallbacks after.\n const releaseFirst = held\n ? `Close the file and open it again to release the columns it is holding, which is the direct remedy. `\n : '';\n\n let advice;\n if (nothingFits) {\n advice =\n `No row count fits this budget - ${fixedCost} it, so ${knob} cannot help. ` +\n (containerBound\n ? `${release}the container's memory limit.`\n : `${release}the heap with --max-old-space-size, or raise memorySafetyFactor.`);\n } else if (containerBound) {\n advice =\n releaseFirst +\n `The binding limit is the container's, so raising --max-old-space-size would let V8 grow past it and be killed by the OOM killer instead. Set it below the container limit, raise the limit, or hold fewer rows with ${knob} (recommended: ${formatCount(recommendedValue)} rows or less).`;\n } else {\n advice =\n releaseFirst +\n `Try holding fewer rows using the ${knob} parameter (recommended: ${formatCount(recommendedValue)} rows or less), or raise the heap with --max-old-space-size.`;\n }\n\n // Every suggestion is read back through this same check before it is offered - that is what the\n // bisections above do - so following one gives a read that fits. A `fields` suggestion is the one\n // this function cannot make: it does not know what each field costs, only what the selection does.\n // `checkRead` makes it, from the header, and adds it.\n const suggestions = [];\n\n if (!nothingFits) {\n suggestions.push({option: knob, value: recommendedValue});\n }\n\n // Raising the heap is advice only where the heap is what bound it. Under a container limit it makes\n // the kill more likely rather than less, which is what the prose above says at length.\n if (!containerBound) {\n // `--max-old-space-size=N` makes `getHeapLimit()` report about N plus the overstatement, and\n // `usableOldSpaceLimit()` takes the overstatement back off - so the usable budget is N itself, and\n // adding the overstatement here counted it twice. It asked for 192MB more than the read needs,\n // every time.\n //\n // Checked rather than asserted, like every other suggestion: the value is the smallest whole\n // megabyte whose budget covers the estimate, and the loop below steps up until it does, so the\n // arithmetic above cannot be subtly wrong without the answer being wrong too.\n let needed = Math.ceil(estimatedMemory / safetyFactor / (1024 * 1024));\n\n while (Math.max(needed * 1024 * 1024, MINIMUM_BUDGET_BYTES) * safetyFactor < estimatedMemory) {\n needed += 1;\n }\n\n suggestions.push({nodeOption: '--max-old-space-size', value: needed});\n }\n\n return {\n fits: false,\n reason: 'memory',\n estimate: {heapBytes: heapMemory, externalBytes: externalMemory, readBytes},\n budget: budgetOf(budget, tightest, safetyFactor),\n // The symbol term is six times the bytes on disk, an overhead measured across files rather than\n // derived, so any read with symbols in it is an estimate and says so. Only a read that decodes\n // nothing can be exact.\n exact: symbolTableSize === 0,\n suggestions,\n refusal: {\n message:\n `Insufficient memory to load file safely. ` +\n `${retainedIsTheReason ? 'Columns held' : 'Symbol table'}: ${sizeMB}MB, Estimated memory needed: ${estimatedMB}MB, Available: ${availableMB}MB (limited by ${limitingFactor}, which bounds ${limitingScope}; considered: ${budgetBreakdown}; observed but not used: ${observedBreakdown}). ` +\n advice,\n context: {\n symbolTableSize,\n symbolTableSizeMB: sizeMB,\n // Whether that figure is the file's symbol table or what an open file is still holding. A\n // paging read is charged for every column any of its pages decoded and kept, so a caller\n // branching on the refusal needs to know which of the two it is looking at - the remedies\n // differ, and for this one releasing is a remedy where raising the limit is only a workaround.\n holdsDecodedColumns: retainedIsTheReason,\n retainedSymbolBytes: retainedBytes,\n estimatedMemoryMB: estimatedMB,\n availableMemoryMB: availableMB,\n heapLimitMB,\n reportedHeapLimitMB,\n availableRamMB,\n limitingFactor,\n limitingScope,\n memoryBudget: budget.candidates,\n memoryObserved: budget.observed,\n columnCount,\n totalRows,\n maxRows,\n recommendedMaxRows,\n // Only present when a chunk size is what overflowed, so a caller cannot mistake one\n // recommendation for the other.\n ...(chunked ? {rowsLive, recommendedChunkSize: recommendedChunk} : {}),\n },\n },\n };\n }\n\n return {\n fits: true,\n estimate: {heapBytes: heapMemory, externalBytes: externalMemory, readBytes},\n budget: budgetOf(budget, tightest, safetyFactor),\n exact: symbolTableSize === 0,\n suggestions: [],\n };\n}\n\n/**\n * The documented half of an answer: everything but the refusal the wrapper throws from.\n *\n * @param {any} answer The answer `checkMemory` returned.\n * @return {any} The same, without `refusal`.\n */\nfunction answerOf(answer) {\n // eslint-disable-next-line no-unused-vars\n const {refusal, ...rest} = answer;\n\n return rest;\n}\n\n/**\n * The budget half of an answer, built the same way whether the read fits or not.\n *\n * `bound` and `allowedBytes` both describe `tightest`, so they cannot disagree with each other, and\n * `processBytes` is whatever candidate bounds the process rather than only a container's - on a runtime\n * with no usable heap limit the process is bounded by total system memory, and reporting `bound` as\n * `process` beside a `processBytes` of null said two things about one answer.\n *\n * @param {{candidates: Array<{source: string, bytes: number}>, observed: Array<{source: string,\n * bytes: number}>}} budget What `getMemoryBudget` measured.\n * @param {{source: string, bytes: number, heapOnly: boolean, allowed?: number}} tightest The candidate\n * with the least room left.\n * @param {number} safetyFactor The fraction of it this read may use.\n * @return {any} The budget half.\n */\nfunction budgetOf(budget, tightest, safetyFactor) {\n // Not named `process`: this module reads `process.constrainedMemory()` and `process.versions`, and a\n // local of that name here would shadow the global for anything added to this function later.\n const processLimit = budget.candidates.find((candidate) => candidate.source !== 'V8 heap limit');\n\n return {\n heapBytes: usableOldSpaceLimit(),\n processBytes: processLimit ? processLimit.bytes : null,\n bound: tightest.heapOnly ? 'heap' : 'process',\n safetyFactor,\n allowedBytes: tightest.allowed ?? tightest.bytes * safetyFactor,\n candidates: budget.candidates,\n observed: budget.observed,\n };\n}\n\n/**\n * Formats a row count for a human reading a diagnostic.\n *\n * Pinned to `en-US` rather than left to `toLocaleString()`'s default, which follows the host's\n * locale. The messages here are English prose, so a number grouped by the machine's convention was\n * inconsistent with the sentence around it - and worse, it made the same message differ between\n * platforms: `9,999,999` on the Linux and macOS runners against `9 999 999` on the Windows ones,\n * where the separator is a narrow no-break space. That is invisible until something matches on the\n * text. A test of this module's warning did, and passed everywhere it was run before failing all\n * three Windows legs in CI.\n *\n * The same property matters outside tests: a diagnostic that reads the same on every platform is\n * one a caller can grep for in a log aggregator collecting from all three.\n *\n * @param {number} value The count.\n * @return {string} The count, grouped the same way everywhere.\n */\nfunction formatCount(value) {\n return value.toLocaleString('en-US');\n}\n\n/**\n * Emits a warning for large symbol tables when loading all rows.\n * Warning threshold scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {number} [columnCount=0] Columns per row, so the reported figure matches the check\n */\nexport function warnLargeSymbolTable(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount = 0,\n materialisesRows = true,\n wholeSymbols = false,\n) {\n // Dynamic warning threshold: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n // 12.5% of the budget the check uses, not of the figure v8 reports. Thresholding on the\n // reported limit made the warning fire later than the refusal it is meant to precede, and by\n // the widest margin on the small heaps where the 192MB of non-old-space is most of it.\n const LARGE_SYMBOL_TABLE_WARNING = usableOldSpaceLimit() * 0.125;\n\n if (symbolTableSize <= LARGE_SYMBOL_TABLE_WARNING) {\n return;\n }\n\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n // Same estimate the check uses. Without columnCount this printed the symbol table's cost\n // alone - roughly 3.6GB where the check had just computed 5.2GB - and a caller sizing\n // --max-old-space-size from the warning would pick a heap far too small.\n const estimatedMemory = estimateMemoryUsage(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount,\n materialisesRows,\n null,\n wholeSymbols,\n );\n\n // The second condition is the cost of *this* read, not whether the caller happened to bound it.\n //\n // It used to be `maxRows === null || maxRows >= totalRows` - \"you asked for everything\". That is\n // a statement about which option was passed, and it came apart when `offset` arrived:\n // `{offset: 1}` on a ten-million-row file materialises 9,999,999 rows and reports a row count\n // one short of the total, so the warning about the memory that costs was silent in exactly the\n // case it exists for. Thresholding the estimate instead is the same answer for every shape that\n // existed before - a full read still warns, a small `maxRows` still does not, because the symbol\n // term is discounted by sqrt(rows/totalRows) - and it is right for the shapes that did not.\n if (estimatedMemory <= LARGE_SYMBOL_TABLE_WARNING) {\n return;\n }\n\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const warnMB = Math.round(LARGE_SYMBOL_TABLE_WARNING / 1024 / 1024);\n\n console.warn(\n `⚠️ Large symbol table detected (${sizeMB}MB > ${warnMB}MB threshold). ` +\n `This read materialises ${formatCount(rowsToLoad)} of ${formatCount(totalRows)} rows ` +\n `and will use ~${estimatedMB}MB RAM. ` +\n `Reading fewer rows - with limit, maxRows, or a narrower offset window - lowers the row cost, ` +\n `though the symbol table is read in full either way.`,\n );\n}\n","// @ts-check\n\nimport {QvdCorruptedError, QvdValidationError} from '../QvdErrors.js';\nimport {getHeapLimit} from './memoryUtils.js';\nimport {MAX_BIT_WIDTH} from './bitUtils.js';\n\n/**\n * A number from the header, read as the whole number it is written as, or NaN when it is not written as\n * one.\n *\n * `parseInt` read the longest prefix it could: `1e18` as 1, `605.9` as 605, `0x10` as 0, and an element\n * written twice - which xml2js hands over as an array - as its first value, because the array stringifies\n * with commas. Each read as an ordinary number. `readMetadata` reported a 606-row file as holding 1, 605\n * or 0 rows, and a `BitOffset` written twice read 389 of `misc/small.qvd`'s 606 cells from the wrong\n * bits, with nothing thrown.\n *\n * Qlik writes every number in a header as plain decimal digits - all 216 fields of the 30 Qlik-written\n * QVDs in the repository do - and so does this library. Whitespace around the digits is allowed: xml2js\n * keeps it, and it cannot be read two ways.\n *\n * NaN rather than a throw, so each number keeps the validator, and the message, it already had. Every\n * number the reader takes from a header comes through here, which is also what stops `readMetadata` and\n * the reads that decode rows from reading one header two ways.\n *\n * @param {unknown} value The element's value, as xml2js gives it.\n * @return {number} The number, or NaN. Never -0.\n */\nexport function headerInteger(value) {\n if (typeof value !== 'string' || !/^\\s*-?\\d+\\s*$/.test(value)) {\n return NaN;\n }\n\n const number = Number(value);\n\n // `-0` is a whole number, and means the zero every comparison below expects.\n return number === 0 ? 0 : number;\n}\n\n/**\n * Validates that a parsed XML header actually describes a QVD, and returns its fields.\n *\n * `parseStringPromise` succeeds on any well-formed XML, and a QVD whose header has been damaged\n * into a fragment parses into an object rooted at whatever element survived - `{Thou: ''}` for\n * `__tests__/data/misc/damaged.qvd`. The `!headerObj` check beside each call site only covers XML\n * that did not parse at all, so the reader indexed straight into a missing `QvdTableHeader` and\n * raised a bare `TypeError`, reporting an ordinary corrupt file as a bug in this library.\n *\n * `Offset` is range-checked here because nothing downstream checks it: an unusable one makes the\n * index table offset NaN, which `_planIndexTable` reads as falsy and reports as the file having\n * been loaded out of order. `RecordByteSize` and `NoOfRecords` are deliberately left alone -\n * `validateIndexTableMetadata` and `validateRecordCount` already reject both the missing and the\n * malformed cases with a more specific message, and repeating the check here would replace it\n * with a vaguer one.\n *\n * The field list is checked here as well, and every field's name. Both places that parse a header\n * call this, and the first - the one a read of rows makes before it reads anything large - resolves\n * the caller's field selection against the names, before the second has run. Checked only in the\n * second, a missing name met that selection first and was reported as a column the caller had asked\n * for wrongly, rather than as a broken header.\n *\n * @param {any} headerObj The parsed XML header.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} stage Stage name recorded in the error context.\n * @return {Array<any>} Every field header, in file order.\n * @throws {QvdCorruptedError} If the header is not a usable QVD table header.\n */\nexport function validateHeaderStructure(headerObj, filePath, stage) {\n const tableHeader = headerObj?.['QvdTableHeader'];\n\n // `typeof null` is 'object' and an empty `<QvdTableHeader/>` parses to '' rather than to an\n // object, so neither case is caught by a truthiness or a typeof test on its own.\n if (tableHeader === null || typeof tableHeader !== 'object' || Array.isArray(tableHeader)) {\n throw new QvdCorruptedError('The XML header contains no usable QvdTableHeader element', {\n rootElements: headerObj && typeof headerObj === 'object' ? Object.keys(headerObj) : [],\n file: filePath,\n stage,\n });\n }\n\n const symbolTableLength = headerInteger(tableHeader['Offset']);\n\n if (isNaN(symbolTableLength) || !Number.isSafeInteger(symbolTableLength) || symbolTableLength < 0) {\n throw new QvdCorruptedError('Invalid symbol table offset', {\n offset: tableHeader['Offset'],\n file: filePath,\n stage,\n });\n }\n\n // A header with no field elements, validated here rather than at each use.\n //\n // Three places downstream normalised the field list with `if (!Array.isArray(fields)) fields =\n // [fields]`, which turns an absent `<Fields/>` into `[undefined]` and then dereferences it - a bare\n // TypeError from the middle of the reader where readMetadata, which checked, reported the file as\n // corrupt. A header that declares no fields is a broken header, not a table with no columns, and\n // `columnCount: 0` for it would be a plausible answer to the wrong question.\n const fields = tableHeader['Fields']?.['QvdFieldHeader'];\n const fieldList = fields === undefined || fields === null ? [] : Array.isArray(fields) ? fields : [fields];\n\n if (fieldList.length === 0) {\n throw new QvdCorruptedError('The QVD file header declares no fields', {\n file: filePath,\n stage,\n });\n }\n\n // Counting the entries is not enough, because a `<QvdFieldHeader>` that is empty or holds text\n // instead of child elements parses to a string, and the normalisation above counts a string as one\n // perfectly good field. Nothing then reads it as anything but an object: readMetadata reported\n // `columns: [null], columnCount: 1` for an eight-column file, which is indistinguishable from a real\n // one-column QVD, while fromQvd refused the same file as corrupt several steps later and blamed a\n // symbol offset. That divergence is the thing the metadata path is designed not to produce, so the\n // entries are checked where they are counted.\n const malformedIndex = fieldList.findIndex(\n (field) => field === null || typeof field !== 'object' || Array.isArray(field),\n );\n\n if (malformedIndex !== -1) {\n throw new QvdCorruptedError('The QVD file header declares a field with no properties', {\n fieldIndex: malformedIndex,\n fieldCount: fieldList.length,\n file: filePath,\n stage,\n });\n }\n\n // Every field needs a name, and one no other field has.\n //\n // A missing name read as an `undefined` column, and one holding an element as an object; a\n // `<FieldName>` written twice read as an array. Two fields of one name read as two columns of it,\n // and `at(row, name)`, `select(name)` and a `fields` selection answered about the first and ignored\n // the second - which is why `selectFields` refuses a name listed twice. Every read reports the\n // names, readMetadata included, so every read refuses them. None of the Qlik-written QVDs in the\n // repository has either, and this library's writer refuses both.\n /** @type {Map<string, number>} */\n const seen = new Map();\n\n fieldList.forEach((field, fieldIndex) => {\n const name = field['FieldName'];\n\n if (typeof name !== 'string' || name === '') {\n throw new QvdCorruptedError('The QVD file header declares a field with no usable name', {\n fieldIndex,\n fieldName: name,\n file: filePath,\n stage,\n });\n }\n\n if (seen.has(name)) {\n throw new QvdCorruptedError('The QVD file header declares two fields with the same name', {\n field: name,\n fieldIndexes: [seen.get(name), fieldIndex],\n file: filePath,\n stage,\n });\n }\n\n seen.set(name, fieldIndex);\n });\n\n return fieldList;\n}\n\n/**\n * Validates symbol table size during initial file read (early check).\n * This is the first-pass validation in _readData for lazy loading.\n * Limit scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} [retainedBytes=0] Of `symbolTableLength`, the bytes belonging to columns an earlier\n * read decoded and kept that this one does not select. It decides whether the columns being held are\n * what breached the ceiling - which \"is this a paging read\" cannot answer, since that is true from the\n * moment paging is switched on and before any page has decoded anything.\n * @throws {QvdValidationError} If symbol table exceeds dynamic limit\n */\nexport function validateSymbolTableSizeEarly(symbolTableLength, filePath, retainedBytes = 0) {\n // Dynamic limit: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n const heapLimit = getHeapLimit();\n const MAX_SYMBOL_TABLE_SIZE = heapLimit * 0.125;\n\n if (symbolTableLength > MAX_SYMBOL_TABLE_SIZE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(MAX_SYMBOL_TABLE_SIZE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n // A paging read reaches this with what its pages have decoded and kept, not with the file's table, so\n // the standard advice is wrong twice over for it: the cardinality is not the point, and \"load the\n // full file without a row window\" is the opposite of what a caller paging a 30 GB file wants. What\n // helps there is letting go of the columns already held.\n // Only when letting go of them would bring it back under. A first page whose own column is too big\n // is over the ceiling on its own, and telling that caller to close and reopen sends them round a\n // loop: nothing is released and the retry breaches it again at the same number.\n if (retainedBytes > 0 && symbolTableLength - retainedBytes <= MAX_SYMBOL_TABLE_SIZE) {\n throw new QvdValidationError(\n `Columns held too large (${sizeMB}MB exceeds ${maxMB}MB limit). ` +\n `This open file is holding the columns its pages have decoded, and they have grown past the ` +\n `ceiling rather than the file's own symbol table being large. ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 12.5% = ${maxMB}MB). ` +\n `Consider: (1) closing the file and opening it again, which releases what the pages decoded, ` +\n `(2) paging over fewer columns with fields, or (3) increasing heap size with --max-old-space-size.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n holdsDecodedColumns: true,\n retainedSymbolBytes: retainedBytes,\n maxAllowed: MAX_SYMBOL_TABLE_SIZE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n reason: 'memory',\n },\n );\n }\n\n throw new QvdValidationError(\n `Symbol table too large (${sizeMB}MB exceeds ${maxMB}MB limit for lazy loading). ` +\n `This QVD file contains extremely high-cardinality fields. ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 12.5% = ${maxMB}MB). ` +\n // \"without a row window\" rather than \"without maxRows\": a window can be spelled with\n // maxRows, limit, offset, or an offset and a limit together, and all four reach this\n // check. Naming one of them tells a caller who passed `offset` to remove something they\n // did not pass.\n `Consider: (1) loading the full file without a row window - maxRows, limit or offset - since the symbol table is read in full either way, (2) increasing heap size with --max-old-space-size, or (3) aggregating high-cardinality fields.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n // Present and false, not absent. A caller told it can branch on this has to find it on both\n // refusals, or the branch reads `undefined` for the commoner of the two.\n holdsDecodedColumns: false,\n retainedSymbolBytes: retainedBytes,\n maxAllowed: MAX_SYMBOL_TABLE_SIZE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 12.5,\n },\n );\n }\n}\n\n/**\n * Validates symbol table size limits to prevent out-of-memory conditions.\n * This is the comprehensive validation in _parseSymbolTable.\n * Absolute ceiling scales with configured heap size (50% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} totalRows Total number of rows in the file\n * @throws {QvdValidationError} If symbol table exceeds safety limits\n */\nexport function validateSymbolTableSize(symbolTableLength, filePath, totalRows) {\n // Dynamic absolute ceiling: 50% of configured heap size\n // Examples: 4GB heap = 2GB, 8GB heap = 4GB, 16GB heap = 8GB, 32GB heap = 16GB\n const heapLimit = getHeapLimit();\n const ABSOLUTE_MAX_SYMBOL_TABLE = heapLimit * 0.5;\n\n if (symbolTableLength > ABSOLUTE_MAX_SYMBOL_TABLE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(ABSOLUTE_MAX_SYMBOL_TABLE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table exceeds absolute maximum size (${sizeMB}MB > ${maxMB}MB). ` +\n `This QVD file has pathological cardinality (likely a data modeling issue). ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 50% = ${maxMB}MB). ` +\n `Consider: (1) increasing heap size with --max-old-space-size, (2) aggregating high-cardinality fields, (3) splitting the data, or (4) using a different format.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: ABSOLUTE_MAX_SYMBOL_TABLE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 50,\n totalRows,\n },\n );\n }\n}\n\n/**\n * Validates field metadata before processing to prevent buffer overflow attacks.\n *\n * The symbol area has to be inside the symbol table, and `NoOfSymbols` has to be a whole number. Whether\n * the area holds that many symbols is for the parse to find out, which is the only thing that walks them.\n * A count that cannot even be read is refused here, for every field, like an unreadable `Offset` or\n * `Length`, so a read of other fields only does not accept a header the full read refuses.\n *\n * @param {any} field Field metadata object\n * @param {number} symbolBufferLength Length of the symbol buffer\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field metadata is invalid\n */\nexport function validateFieldMetadata(field, symbolBufferLength, filePath) {\n const symbolsOffset = headerInteger(field['Offset']);\n const symbolsLength = headerInteger(field['Length']);\n const symbolCount = headerInteger(field['NoOfSymbols']);\n\n // Validate offset is a valid number and within bounds\n if (isNaN(symbolsOffset) || !Number.isSafeInteger(symbolsOffset) || symbolsOffset < 0) {\n throw new QvdCorruptedError('Invalid symbol offset', {\n field: field['FieldName'],\n offset: symbolsOffset,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate length is a valid number and non-negative\n if (isNaN(symbolsLength) || !Number.isSafeInteger(symbolsLength) || symbolsLength < 0) {\n throw new QvdCorruptedError('Invalid symbol length', {\n field: field['FieldName'],\n length: symbolsLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate the symbol count is a valid number and non-negative\n if (isNaN(symbolCount) || !Number.isSafeInteger(symbolCount) || symbolCount < 0) {\n throw new QvdCorruptedError('Invalid symbol count', {\n field: field['FieldName'],\n noOfSymbols: symbolCount,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate that offset + length doesn't exceed buffer size\n if (symbolsOffset + symbolsLength > symbolBufferLength) {\n throw new QvdCorruptedError('Symbol data extends beyond buffer', {\n field: field['FieldName'],\n offset: symbolsOffset,\n length: symbolsLength,\n bufferSize: symbolBufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n}\n\n/**\n * A field's claim on a range of bytes or bits: where it starts, and how many it takes.\n *\n * @typedef {Object} FieldRange\n * @property {string} field The field's name.\n * @property {number} start The first byte or bit.\n * @property {number} length How many.\n */\n\n/**\n * The first two of a set of ranges that overlap, or null when none do.\n *\n * Empty ranges are left out, because they claim nothing: every field of `misc/empty_qvd.qvd` starts its\n * symbols at byte 0 with none to hold, and two of them are zero bits wide at bit 0.\n *\n * @param {Array<FieldRange>} ranges The ranges, in field order.\n * @return {[FieldRange, FieldRange]|null} The range reaching furthest so far, and the first to start\n * inside it. Ranges that start together are taken in field order.\n */\nfunction firstOverlap(ranges) {\n const claimed = ranges.filter((range) => range.length > 0).sort((a, b) => a.start - b.start);\n /** @type {FieldRange|null} */\n let furthest = null;\n\n for (const range of claimed) {\n if (furthest !== null && range.start < furthest.start + furthest.length) {\n return [furthest, range];\n }\n\n if (furthest === null || range.start + range.length > furthest.start + furthest.length) {\n furthest = range;\n }\n }\n\n return null;\n}\n\n/**\n * Validates that no two fields' symbol areas overlap.\n *\n * Each field's symbols are read from the area its `Offset` and `Length` give, and `validateFieldMetadata`\n * checks only that the area is inside the symbol table. Two fields whose areas overlap each read some of\n * the same bytes as their own symbols: `ProductName` pointed at `ProductKey`'s area in `misc/small.qvd`\n * read all 606 of its values as `ProductKey`'s, with nothing thrown, because every index still addressed\n * a symbol. Qlik lays the areas end to end, in field order, from byte 0, and so does this library.\n *\n * Only an overlap is refused. A gap between two areas takes nothing from either field. An area cut short\n * leaves its field fewer symbols, and a row that points past them is refused where it is decoded.\n *\n * Call it once `validateFieldMetadata` has passed every field, which is what makes the numbers usable.\n *\n * @param {Array<any>} fields Every field header in the file.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If two fields' symbol areas overlap.\n */\nexport function validateSymbolAreas(fields, filePath) {\n const overlap = firstOverlap(\n fields.map((field) => ({\n field: field['FieldName'],\n start: headerInteger(field['Offset']),\n length: headerInteger(field['Length']),\n })),\n );\n\n if (overlap !== null) {\n const [first, second] = overlap;\n\n throw new QvdCorruptedError('Symbol areas overlap', {\n field: second.field,\n offset: second.start,\n length: second.length,\n overlaps: first.field,\n overlapsOffset: first.start,\n overlapsLength: first.length,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n}\n\n/**\n * Validates that no two fields' bits overlap within a record.\n *\n * Each field's stored index is read from the bits its `BitOffset` and `BitWidth` give, and\n * `validateFieldBitMetadata` checks only that they are inside the record. Two fields whose bits overlap\n * each read some of the same bits as their own: `Weight`'s bits pointed at `ListPrice`'s in\n * `misc/small.qvd` read 391 of its 606 values wrong, with nothing thrown, wherever `ListPrice`'s index\n * was also one of `Weight`'s symbols. Qlik packs a record's fields without overlaps, though not in field\n * order, and so does this library; a field zero bits wide claims no bits at all.\n *\n * Call it once `validateFieldBitMetadata` has passed every field, which is what makes the numbers usable.\n *\n * @param {Array<any>} fields Every field header in the file.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If two fields' bits overlap.\n */\nexport function validateBitFields(fields, filePath) {\n const overlap = firstOverlap(\n fields.map((field) => ({\n field: field['FieldName'],\n start: headerInteger(field['BitOffset']),\n length: headerInteger(field['BitWidth']),\n })),\n );\n\n if (overlap !== null) {\n const [first, second] = overlap;\n\n throw new QvdCorruptedError('Bit fields overlap', {\n field: second.field,\n bitOffset: second.start,\n bitWidth: second.length,\n overlaps: first.field,\n overlapsBitOffset: first.start,\n overlapsBitWidth: first.length,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n\n/**\n * Validates a header's declared record count.\n *\n * Extracted so the metadata-only read applies exactly the same rule as a load. When they were\n * separate, `readMetadata` coerced an unusable `NoOfRecords` to zero while `fromQvd` refused the\n * same file - so a header with the element deleted reported \"0 rows\" rather than \"this header is\n * broken\", which is indistinguishable from a genuinely empty QVD at the call site.\n *\n * @param {number} totalRows The parsed NoOfRecords.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} [stage='parseIndexTable'] Stage name recorded in the error context.\n * @throws {QvdCorruptedError} If the count is not a non-negative safe integer.\n */\nexport function validateRecordCount(totalRows, filePath, stage = 'parseIndexTable') {\n if (isNaN(totalRows) || !Number.isSafeInteger(totalRows) || totalRows < 0) {\n throw new QvdCorruptedError('Invalid number of records', {\n totalRows,\n file: filePath,\n stage,\n });\n }\n}\n\n/**\n * Validates a header's declared record size.\n *\n * Extracted, like `validateRecordCount`, so a windowed read refuses an unusable one with the message a\n * whole-file read gives. A windowed read has to check it before it sizes the buffer the window is read\n * into, which is earlier than `validateIndexTableMetadata` runs, and it used to say `Invalid header value:\n * RecordByteSize` there - one header, two answers, depending on the window a caller asked for.\n *\n * @param {number} recordSize The parsed RecordByteSize.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} [stage='parseIndexTable'] Stage name recorded in the error context.\n * @throws {QvdCorruptedError} If the size is not a non-negative safe integer.\n */\nexport function validateRecordSize(recordSize, filePath, stage = 'parseIndexTable') {\n if (isNaN(recordSize) || !Number.isSafeInteger(recordSize) || recordSize < 0) {\n throw new QvdCorruptedError('Invalid record byte size', {\n recordSize,\n file: filePath,\n stage,\n });\n }\n}\n\n/**\n * Validates index table metadata and bounds.\n *\n * @param {number} recordSize Size of a single record in bytes\n * @param {number} totalRows Total number of rows\n * @param {number} indexTableLength Length of the index table\n * @param {number} indexTableOffset Offset to the index table\n * @param {number} bufferLength Length of the buffer\n * @param {number} rowsToLoad Number of rows to load\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number|null} [fileSize] Actual size of the file on disk, when known. Used to detect a\n * header that describes more data than the file contains.\n * @param {number} [windowFirstRow=0] File row the decode starts at. The rows before it still have\n * to exist in the declared table, so the table has to reach `windowFirstRow + rowsToLoad`.\n * @param {number} [bufferFirstRow=0] File row the loaded buffer's index table starts at. A\n * windowed read loads only the records it wants, so this is not always zero, and the two row\n * numbers bound different things: the first bounds the file, the second bounds the buffer.\n * @throws {QvdCorruptedError} If index table metadata is invalid\n */\nexport function validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n indexTableOffset,\n bufferLength,\n rowsToLoad,\n filePath,\n fileSize = null,\n windowFirstRow = 0,\n bufferFirstRow = 0,\n) {\n validateRecordSize(recordSize, filePath);\n validateRecordCount(totalRows, filePath);\n\n // Allow recordSize of 0 or 1 only when there are no records (empty QVD)\n // Qlik Sense uses recordSize=1 for empty QVDs\n if (recordSize === 0 && totalRows > 0) {\n throw new QvdCorruptedError('Record byte size cannot be zero when records exist', {\n recordSize,\n totalRows,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate recordSize is reasonable (max 1MB per record)\n if (recordSize > 1048576) {\n throw new QvdCorruptedError('Record byte size exceeds maximum', {\n recordSize,\n maxSize: 1048576,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table length\n if (isNaN(indexTableLength) || !Number.isSafeInteger(indexTableLength) || indexTableLength < 0) {\n throw new QvdCorruptedError('Invalid index table length', {\n length: indexTableLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table start offset doesn't extend beyond buffer\n if (indexTableOffset > bufferLength) {\n throw new QvdCorruptedError('Index table offset beyond buffer', {\n indexTableOffset,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // The index table must be exactly as long as the record count implies. Every QVD produced by\n // Qlik or by this library satisfies this, so a mismatch means the header is inconsistent.\n // Checking it catches corrupt headers that would otherwise decode misaligned rows.\n if (indexTableLength !== totalRows * recordSize) {\n throw new QvdCorruptedError('Index table length inconsistent with record count', {\n indexTableLength,\n expectedLength: totalRows * recordSize,\n totalRows,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate the index table against the actual file when its size is known.\n //\n // Comparing against the in-memory buffer instead is wrong in both directions: during a lazy\n // load the buffer is deliberately truncated, so valid large files were rejected as corrupt,\n // while a truncated file whose header claims more data was accepted and silently returned\n // fewer rows than the header declares.\n if (fileSize !== null) {\n if (indexTableOffset + indexTableLength > fileSize) {\n throw new QvdCorruptedError('Index table extends beyond the end of the file', {\n indexTableOffset,\n indexTableLength,\n fileSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n }\n\n // Ensure the loaded buffer actually holds the rows we were asked to parse.\n //\n // The window's records start `(windowFirstRow - bufferFirstRow)` records into the buffer's index\n // table, which is zero for a read that starts at row 0 and not zero for one that does not.\n const requiredIndexBytes = rowsToLoad * recordSize;\n const bufferRecordStart = (windowFirstRow - bufferFirstRow) * recordSize;\n if (indexTableOffset + bufferRecordStart + requiredIndexBytes > bufferLength) {\n throw new QvdCorruptedError('Index table truncated', {\n indexTableOffset,\n requiredBytes: requiredIndexBytes,\n availableBytes: Math.max(0, bufferLength - indexTableOffset - bufferRecordStart),\n rowsToLoad,\n windowFirstRow,\n bufferFirstRow,\n recordSize,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Ensure the index table reaches the end of the window, not merely as far as its length.\n //\n // Measured against the window's last row rather than its row count: `{offset: 10, limit: 5}`\n // needs fifteen records to exist, and comparing five against the table's length would accept a\n // file that holds only twelve - decoding three real rows and two of whatever follows.\n const requiredTableBytes = (windowFirstRow + rowsToLoad) * recordSize;\n if (indexTableLength < requiredTableBytes) {\n throw new QvdCorruptedError('Index table length smaller than required', {\n indexTableLength,\n requiredBytes: requiredTableBytes,\n rowsToLoad,\n windowFirstRow,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n\n/**\n * Validates a field's bit offset, bit width and bias for index table parsing.\n *\n * @param {any} field Field metadata object\n * @param {number} recordSize Size of a single record in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field bit metadata is invalid\n */\nexport function validateFieldBitMetadata(field, recordSize, filePath) {\n const bitOffset = headerInteger(field['BitOffset']);\n const bitWidth = headerInteger(field['BitWidth']);\n\n // Validate bitOffset\n if (isNaN(bitOffset) || !Number.isSafeInteger(bitOffset) || bitOffset < 0) {\n throw new QvdCorruptedError('Invalid bit offset', {\n field: field['FieldName'],\n bitOffset,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth\n if (isNaN(bitWidth) || !Number.isSafeInteger(bitWidth) || bitWidth < 0) {\n throw new QvdCorruptedError('Invalid bit width', {\n field: field['FieldName'],\n bitWidth,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias.\n //\n // It is added to every decoded index inside an Int32Array, and Int32Array coerces NaN to 0 -\n // so an absent or non-numeric Bias made a file read back as plausible wrong values rather\n // than as an error. A blank <Bias> on a nullable column turned every NULL and every symbol\n // above the first into the first symbol, silently. Validated here alongside the other two\n // because the three travel together and are trusted together.\n const bias = headerInteger(field['Bias']);\n\n if (isNaN(bias) || !Number.isSafeInteger(bias)) {\n throw new QvdCorruptedError('Invalid bias', {\n field: field['FieldName'],\n bias: field['Bias'],\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth against what a stored index can be.\n //\n // Indices are kept in an Int32Array, so the value has to fit in a positive 32-bit integer.\n // The bound is not a limitation in practice - 31 bits addresses two billion symbols in one\n // field - and refusing is the safe direction: a 32-bit width lets the top of the range wrap\n // to a negative index, which read back as NULL before #125, so the file returned plausible\n // wrong values rather than an error.\n if (bitWidth > MAX_BIT_WIDTH) {\n throw new QvdCorruptedError('Bit width exceeds maximum', {\n field: field['FieldName'],\n bitWidth,\n maxBitWidth: MAX_BIT_WIDTH,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias against what an index can be once it is applied.\n //\n // A field's indices run from `Bias` to `Bias + 2^BitWidth - 1`, and they are kept in an\n // Int32Array, which stores a value outside 32 bits modulo 2^32 rather than refusing it. A wrapped\n // index is not an error but a different index: a Bias of 2^32 - 2 decodes exactly as -2 does, and\n // on `misc/small.qvd` it turned 604 of a column's 606 values into other symbols and two into\n // NULLs, with nothing thrown. Below -2^31 the same wrap turns what should be negative - NULL -\n // into a real symbol. Refusing the Bias is what lets every later check trust that the index it\n // looks at is the one the file holds.\n if (bias < -(2 ** 31) || bias + 2 ** bitWidth - 1 > 2 ** 31 - 1) {\n throw new QvdCorruptedError('Bias out of range', {\n field: field['FieldName'],\n bias,\n bitWidth,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias against the two values a QVD uses.\n //\n // Qlik writes 0 for a field without NULLs and -2 for one with them - 207 and 9 of the 216 fields in\n // the 30 Qlik-written QVDs in the repository - and so does this library. Any other value that fits in\n // 32 bits passed every check above and shifted the column. A Bias of 0 read as -1 turned stored index 0\n // into the NULL marker and every other index into its neighbour's symbol: `misc/small.qvd`'s Color read\n // all 606 of its values wrong, 254 of them as NULL, and no read threw, because every index still\n // addressed a symbol or NULL. -1 is also the one other value a writer might choose on purpose, with NULL\n // at stored index 0 and symbols from 1, and no rule can refuse the damage and keep that, so it is refused\n // too. Checked after the range above, so a Bias that would wrap keeps that diagnosis.\n if (bias !== 0 && bias !== -2) {\n throw new QvdCorruptedError('Bias is neither 0 nor -2', {\n field: field['FieldName'],\n bias,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitOffset + bitWidth doesn't exceed record size in bits\n const recordSizeInBits = recordSize * 8;\n if (bitOffset + bitWidth > recordSizeInBits) {\n throw new QvdCorruptedError('Bit field extends beyond record size', {\n field: field['FieldName'],\n bitOffset,\n bitWidth,\n recordSizeInBits,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n","// @ts-check\n\nimport assert from 'assert';\nimport {QvdCorruptedError, QvdParseError} from '../QvdErrors.js';\n\n/**\n * The longest text one symbol may hold. A damaged file cannot then make the reader decode a string the\n * size of the whole symbol table.\n */\nconst MAX_TEXT_BYTES = 1048576;\n\n/**\n * One field's symbols, as the two halves each can have, decoded straight from the symbol table's bytes.\n *\n * A pure number has a number and no text, a pure string a text and no number, and a dual both. A symbol\n * the two-pass path did not need has neither: nothing was decoded for it, and every symbol a file holds\n * has at least one half, so null in both cannot be mistaken for a value.\n *\n * Two arrays per field rather than an object per symbol. The reader resolves what each symbol reads as\n * from these, once, and nothing else keeps them; a high-cardinality field used to allocate a symbol\n * object, a result object and two typed arrays for every numeric value it held.\n *\n * A read reports what the file holds, unchecked: a damaged file's NaN double reads as NaN, and it is the\n * writer that refuses to store it again.\n *\n * @typedef {Object} FieldSymbols\n * @property {Array<number|null>} numbers Each symbol's number: an int's, a double's or a dual's.\n * @property {Array<string|null>} texts Each symbol's text: a string's or a dual's.\n */\n\n/**\n * How far a search for a text's terminator may reach, and how far into its view the walk may go before\n * the view moves.\n *\n * `Buffer.prototype.indexOf` misreports any position past 2^31 - 1, whether it is where the search\n * starts or where the byte is found. On Node 22 and 24 it returns the position less 2^32, a large\n * negative number, where it should return the index or -1. A symbol area can be larger than that - one\n * field of 2.1 million texts of 1,100 characters is 2.3 GB - and the walk read the negative number as a\n * terminator, moved its position back before the area, and threw a raw `TypeError` on the `undefined` it\n * found there (#122). So on an area larger than `reach` a search runs on a view of at most `reach` bytes,\n * and the view moves up to the current position once the walk is more than `rebaseAfter` bytes into it.\n *\n * `reach` must exceed `rebaseAfter` by more than `MAX_TEXT_BYTES`, so a view always holds as much of a\n * text as the text may hold: a terminator it does not find belongs to a text too long to be read anyway.\n * A parameter rather than a constant only so a test can make it small, and walk every bundled file across\n * many moves, which no test could do at 2 GiB.\n */\nexport const TEXT_SEARCH = Object.freeze({reach: 2 ** 31 - 1, rebaseAfter: 2 ** 30});\n\n/**\n * A search for the next NUL in `area` that stays correct past 2^31 - see `TEXT_SEARCH`.\n *\n * An area no larger than `reach` is searched directly, as it always was.\n *\n * @param {Buffer} area The symbol table up to the end of one field's area.\n * @param {{reach: number, rebaseAfter: number}} limits The view's longest reach, and when it moves.\n * @return {(from: number) => number} Finds the first NUL at or after `from`, and returns its index in\n * `area`, or -1 when the view holds none.\n */\nfunction nulFinder(area, {reach, rebaseAfter}) {\n assert(reach - rebaseAfter > MAX_TEXT_BYTES, 'A text search view must hold the longest text a symbol may have.');\n\n if (area.length <= reach) {\n return (from) => area.indexOf(0, from);\n }\n\n let base = 0;\n let view = area.subarray(0, reach);\n\n return (from) => {\n if (from - base > rebaseAfter) {\n base = from;\n view = area.subarray(base, Math.min(area.length, base + reach));\n }\n\n const found = view.indexOf(0, from - base);\n\n return found === -1 ? -1 : base + found;\n };\n}\n\n/**\n * Where the text starting at `from` ends: the index of its NUL terminator.\n *\n * @param {(from: number) => number} findNul The field's `nulFinder`.\n * @param {number} areaEnd The byte after the field's last.\n * @param {number} from The first byte of the text.\n * @param {string} kind 'String symbol' or 'Dual string symbol', for the error.\n * @param {string} fieldName The field, for the error.\n * @param {string} filePath The file, for the error.\n * @param {number} base Where the buffer's first byte sits in the symbol table - see `parseFieldSymbols`.\n * @return {number} The index of the terminator.\n * @throws {QvdCorruptedError} If the text runs past the longest a symbol may hold, or has no terminator\n * before the end of the field's area.\n */\nfunction textEnd(findNul, areaEnd, from, kind, fieldName, filePath, base) {\n const found = findNul(from);\n\n if ((found === -1 ? areaEnd : found) - from > MAX_TEXT_BYTES) {\n throw new QvdCorruptedError(`${kind} exceeds maximum length`, {\n field: fieldName,\n maxLength: MAX_TEXT_BYTES,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n if (found === -1) {\n throw new QvdCorruptedError(`${kind} not null-terminated`, {\n field: fieldName,\n pointer: base + from,\n areaEnd: base + areaEnd,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return found;\n}\n\n/**\n * Refuses a number that would be read past the end of the field's area.\n *\n * @param {string} message What was being read.\n * @param {number} pointer The first byte of the number.\n * @param {number} areaEnd The byte after the field's last.\n * @param {string} fieldName The field, for the error.\n * @param {string} filePath The file, for the error.\n * @param {number} base Where the buffer's first byte sits in the symbol table - see `parseFieldSymbols`.\n * @return {never}\n * @throws {QvdCorruptedError} Always.\n */\nfunction overflow(message, pointer, areaEnd, fieldName, filePath, base) {\n throw new QvdCorruptedError(message, {\n field: fieldName,\n pointer: base + pointer,\n areaEnd: base + areaEnd,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n}\n\n/**\n * Decodes one field's symbols from the symbol table.\n *\n * Each symbol is a type byte - 1 int, 2 double, 4 string, 5 dual int, 6 dual double - then a 4-byte\n * int or 8-byte double, then a NUL-terminated UTF-8 text, as the type says. A symbol outside `keep` is\n * walked past without decoding, but its length still has to be found, and it is checked exactly as a\n * decoded one is, with the same error: a window changes which symbols are decoded, never whether damage\n * is found or what it is called. A number walked past used to be checked not at all.\n *\n * Every symbol has to end inside the field's own area, `start` to `end`, not merely inside the symbol\n * table. The next field's symbols start where this area ends, so a symbol allowed to run past it is read\n * partly from another field's bytes (#124): a text whose terminator was damaged took the next field's\n * first symbol as the rest of itself, and a number read its last bytes from there, with nothing thrown.\n * Held to the area, the walk ends exactly at `end`.\n *\n * Then the symbols walked have to be as many as the header's `NoOfSymbols` says. A terminator damaged in\n * the middle of the area merges two texts into one that still ends inside it, so the walk ends where it\n * should, one symbol short, and only the count shows it: every row pointing past the merged symbol read\n * its neighbour's value, and a read was refused only if it happened to decode a row pointing at the last\n * symbol, which no longer existed. Qlik and this library both write the count exactly, so any other\n * number is damage too, to the symbols or to the header.\n *\n * @param {Buffer} symbolBuffer The symbol table, or the range of it a read of some fields read.\n * @param {number} start The field's first byte in it.\n * @param {number} end The byte after the field's last, no further than the buffer's end.\n * @param {number} symbolCount How many symbols the header says the area holds: its `NoOfSymbols`.\n * @param {Set<number>|null} keep The symbols to decode, by index, or null for all of them.\n * @param {string} fieldName The field, for errors.\n * @param {string} filePath The file, for errors.\n * @param {{reach: number, rebaseAfter: number}} [search=TEXT_SEARCH] How far a terminator search may\n * reach. Only a test passes anything but the default.\n * @param {number} [base=0] Where `symbolBuffer` starts in the symbol table, added to every position an\n * error reports, so a read of one field's range names the bytes a read of the whole table would name.\n * @return {FieldSymbols} The field's symbols.\n * @throws {QvdCorruptedError} If a symbol runs past the end of the field's area, or the area holds a\n * different number of symbols from `symbolCount`.\n * @throws {QvdParseError} If a type byte is not one of the five.\n */\nexport function parseFieldSymbols(\n symbolBuffer,\n start,\n end,\n symbolCount,\n keep,\n fieldName,\n filePath,\n search = TEXT_SEARCH,\n base = 0,\n) {\n // The buffer up to the end of the field's area and no further, so a search for a terminator cannot find\n // one in the next field's bytes. A view, not a copy.\n //\n // Positions in it are positions in the buffer, which is the whole symbol table for a read of every field\n // and one range of it for a read of some. So an error reports `base` past what it walked, and a caller\n // reading one field of twenty is told the same bytes as a caller reading all twenty (#122).\n const area = symbolBuffer.subarray(0, end);\n const findNul = nulFinder(area, search);\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n let pointer = start;\n\n while (pointer < end) {\n const typeByte = area[pointer++];\n const decode = keep === null || keep.has(numbers.length);\n let number = null;\n let text = null;\n\n switch (typeByte) {\n case 1: {\n if (pointer + 4 > end) {\n overflow('Buffer overflow reading integer symbol', pointer, end, fieldName, filePath, base);\n }\n if (decode) {\n number = area.readInt32LE(pointer);\n }\n pointer += 4;\n break;\n }\n case 2: {\n if (pointer + 8 > end) {\n overflow('Buffer overflow reading double symbol', pointer, end, fieldName, filePath, base);\n }\n if (decode) {\n number = area.readDoubleLE(pointer);\n }\n pointer += 8;\n break;\n }\n case 4: {\n const terminator = textEnd(findNul, end, pointer, 'String symbol', fieldName, filePath, base);\n if (decode) {\n text = area.toString('utf8', pointer, terminator);\n }\n pointer = terminator + 1;\n break;\n }\n case 5:\n case 6: {\n const numberBytes = typeByte === 5 ? 4 : 8;\n if (pointer + numberBytes > end) {\n const read = typeByte === 5 ? 'dual integer symbol' : 'dual double symbol';\n overflow(`Buffer overflow reading ${read}`, pointer, end, fieldName, filePath, base);\n }\n\n const terminator = textEnd(\n findNul,\n end,\n pointer + numberBytes,\n 'Dual string symbol',\n fieldName,\n filePath,\n base,\n );\n if (decode) {\n number = typeByte === 5 ? area.readInt32LE(pointer) : area.readDoubleLE(pointer);\n text = area.toString('utf8', pointer + numberBytes, terminator);\n }\n pointer = terminator + 1;\n break;\n }\n default: {\n throw new QvdParseError('Unknown symbol type byte', {\n typeByte: typeByte.toString(16),\n offset: base + pointer - 1,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n }\n\n numbers.push(number);\n texts.push(text);\n }\n\n // Every read above is held to `end`, so the walk cannot stop anywhere else. Asserted rather than left\n // implicit, because a check relaxed later would let the last symbol run on into the next field's bytes\n // again, and nothing downstream would notice.\n assert(pointer === end, `The symbols of ${fieldName} were walked to byte ${pointer} of an area ending at ${end}.`);\n\n if (numbers.length !== symbolCount) {\n throw new QvdCorruptedError('Symbol count mismatch', {\n field: fieldName,\n symbolCount: numbers.length,\n noOfSymbols: symbolCount,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return {numbers, texts};\n}\n\n/** A keep set that holds nothing, so `parseFieldSymbols` walks every symbol and decodes none. */\nconst DECODE_NOTHING = new Set();\n\n/**\n * How many symbols a field's area holds: the length `parseFieldSymbols` gives its arrays.\n *\n * It is that function told to decode nothing, not a second walk written beside it. The two-pass read\n * uses the count to decide which indices can address a symbol before any symbol is parsed. A count\n * that fell short of the parse by one would leave out a symbol some row needs, and that row would read\n * back `undefined` with nothing thrown, so the count has to come from the same loop. Walking costs each\n * symbol's length check and, for a text, the search for its terminator. The arrays it builds hold\n * nulls and are dropped at once.\n *\n * Being the same loop, it makes the same checks, `symbolCount` included, and refuses a field with the\n * error the parse would give. So what it returns is always `symbolCount`, and yet it is walked rather\n * than taken from the header: until the walk has checked it, the header's number is only what the file\n * claims, and one too large, damaged or not, bounds nothing. The count exists to bound the two-pass\n * read's set of indices on exactly such a file.\n *\n * @param {Buffer} symbolBuffer The whole symbol table.\n * @param {number} start The field's first byte in it.\n * @param {number} end The byte after the field's last, no further than the table's end.\n * @param {number} symbolCount How many symbols the header says the area holds: its `NoOfSymbols`.\n * @param {string} fieldName The field, for errors.\n * @param {string} filePath The file, for errors.\n * @return {number} The field's symbols.\n * @throws {QvdCorruptedError} If a symbol runs past the end of the field's area, or the area holds a\n * different number of symbols from `symbolCount`.\n * @throws {QvdParseError} If a type byte is not one of the five.\n */\nexport function countFieldSymbols(symbolBuffer, start, end, symbolCount, fieldName, filePath, base = 0) {\n return parseFieldSymbols(symbolBuffer, start, end, symbolCount, DECODE_NOTHING, fieldName, filePath, undefined, base)\n .numbers.length;\n}\n","// @ts-check\n\nimport {dualFromSymbol} from '../QvdDual.js';\nimport {isNumericText} from './cellRules.js';\n\n/**\n * @typedef {import('./storedSymbols.js').StoredSymbolsEntry} StoredSymbolsEntry\n */\n\n/**\n * Both halves of each symbol of a field, aligned with its symbols: the text, or null for a pure\n * number, and the number, or null for a pure string.\n *\n * What a columnar read keeps for a field whose cells do not show every half, so a column can answer\n * `textAt` and give a date read as text its serial.\n *\n * @typedef {Object} SymbolHalves\n * @property {ReadonlyArray<string|null>} texts Each symbol's text.\n * @property {ReadonlyArray<number|null>} numbers Each symbol's number.\n */\n\n/**\n * What one field's symbols read as, and what has to be kept so they write back as the same symbols.\n *\n * Runs once per symbol, not once per cell: every row holding a symbol shares the value resolved here.\n *\n * A symbol reads as follows, the representation depending only on its type and the options - never on\n * the other symbols of the field, and never on the window:\n *\n * | Symbol | `'number'` (default) | `'text'` | `'both'` |\n * | --- | --- | --- | --- |\n * | int, double | the number | the number | the number |\n * | string | the string | the string | the string |\n * | string, numeric text, `coerce` on | `Number(text)` | `Number(text)` | `Number(text)` |\n * | dual | its number | its text | a frozen `QvdDual` |\n * | dual, numeric text, `coerce` on | its number | its number | a frozen `QvdDual` |\n * | NULL | null | null | null |\n *\n * A numeric text is one `isNumericText` accepts. `coerce` reaches only a cell that would otherwise be a\n * string: a string symbol in every mode, and a dual under `'text'`. A dual's numeric text reads as the\n * number Qlik *stored*, not as `Number(text)`, so a dual's number is the same in every mode that shows it.\n * The two need not be close. A text that spells the number can still parse to the double beside it -\n * Qlik stores 1.1400000000000001 for `1.14` - and a text that shows it rounded, or shows another value\n * such as a date as `20160113`, parses to a different number altogether.\n *\n * Wherever a cell shows only one half, the symbol is recorded, keyed by the value the cell holds, in\n * symbol order - which for a Qlik file is the order values first appear. That is pass A. Pass B runs\n * only for a field in which pass A recorded something and which also holds pure symbols: a pure\n * symbol that reads as a value already recorded is recorded too, so the writer can see that the value\n * stands for two different symbols and refuse it, rather than silently writing both as one. A Qlik\n * file keeps one symbol per value in a field, so for one pass B finds nothing to add.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols, both halves null where\n * the two-pass path did not decode one.\n * @param {string} field The field name, for the record.\n * @param {'number'|'text'|'both'} mode The `duals` option.\n * @param {boolean} coerce Whether a numeric text reads as a number.\n * @param {boolean} wantHalves Whether to return both halves of every symbol, for a columnar read.\n * @return {{values: Array<any>, entry: StoredSymbolsEntry|null, halves: SymbolHalves|null}} The value of\n * each symbol - undefined where it was filtered out - the field's record entry, or null when every\n * cell shows its whole symbol, and the halves when asked for and the field has a symbol whose cell\n * does not show both.\n */\nexport function resolveFieldSymbols(symbols, field, mode, coerce, wantHalves) {\n const length = symbols.numbers.length;\n const values = new Array(length);\n\n // Pass A's entries, in symbol order. Pushed as they are found rather than marked and collected,\n // because a field read from a Qlik file never needs pass B to add anything.\n /** @type {Array<number|string>} */\n const entryValues = [];\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n let pure = 0;\n let partial = false;\n\n for (let index = 0; index < length; index++) {\n const text = symbols.texts[index];\n const number = symbols.numbers[index];\n\n if (text === null) {\n // Neither half: a symbol the two-pass path did not decode, which no row of the window uses.\n values[index] = number === null ? undefined : number;\n if (number !== null) pure++;\n continue;\n }\n\n if (number === null) {\n if (coerce && isNumericText(text)) {\n values[index] = Number(text);\n entryValues.push(values[index]);\n numbers.push(null);\n texts.push(text);\n partial = true;\n } else {\n values[index] = text;\n pure++;\n }\n\n continue;\n }\n\n partial = true;\n\n if (mode === 'both') {\n // One frozen QvdDual per symbol, shared by every row holding it. Only this mode builds one; the\n // parser never does.\n values[index] = dualFromSymbol(number, text);\n continue;\n }\n\n values[index] = mode === 'number' || (coerce && isNumericText(text)) ? number : text;\n entryValues.push(values[index]);\n numbers.push(number);\n texts.push(text);\n }\n\n /** @type {StoredSymbolsEntry|null} */\n let entry = null;\n\n if (entryValues.length > 0) {\n entry =\n pure > 0 && collides(symbols, values, new Set(entryValues))\n ? collisionEntry(symbols, field, values, mode)\n : Object.freeze({\n field,\n values: Object.freeze(entryValues),\n numbers: Object.freeze(numbers),\n texts: Object.freeze(texts),\n });\n }\n\n return {values, entry, halves: wantHalves && partial ? symbolHalves(symbols) : null};\n}\n\n/**\n * Whether a pure symbol reads as a value pass A recorded - pass B's question.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {Array<any>} values What each symbol reads as.\n * @param {Set<any>} recorded The values pass A recorded. A Set compares by SameValueZero, the same\n * equality the writer's Map uses to look a cell up.\n * @return {boolean} True when one does.\n */\nfunction collides(symbols, values, recorded) {\n for (let index = 0; index < values.length; index++) {\n if (!isPure(symbols, index, values[index])) {\n continue;\n }\n\n if (recorded.has(values[index])) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether a symbol's cell shows the whole symbol: a pure number, or a pure string read as itself.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {number} index The symbol.\n * @param {any} value What it reads as.\n * @return {boolean} True for a pure symbol pass A did not record; false for one never decoded.\n */\nfunction isPure(symbols, index, value) {\n const text = symbols.texts[index];\n const number = symbols.numbers[index];\n\n return text === null ? number !== null : number === null && value === text;\n}\n\n/**\n * A field's record entry when pass B has something to add: pass A's symbols, and every pure symbol\n * that reads as one of their values, all in symbol order.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {string} field The field name.\n * @param {Array<any>} values What each symbol reads as.\n * @param {'number'|'text'|'both'} mode The `duals` option.\n * @return {StoredSymbolsEntry} The frozen entry.\n */\nfunction collisionEntry(symbols, field, values, mode) {\n const recorded = new Set();\n /** @type {Array<boolean>} */\n const inPassA = values.map((value, index) => {\n if ((symbols.numbers[index] === null && symbols.texts[index] === null) || isPure(symbols, index, value)) {\n return false;\n }\n\n // A dual read as a half, or a string coerced to a number. A 'both' dual is its own QvdDual cell.\n const recordedHere = !(mode === 'both' && symbols.texts[index] !== null && symbols.numbers[index] !== null);\n\n if (recordedHere) {\n recorded.add(values[index]);\n }\n\n return recordedHere;\n });\n\n /** @type {Array<number|string>} */\n const entryValues = [];\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n\n for (let index = 0; index < values.length; index++) {\n if (inPassA[index] || (isPure(symbols, index, values[index]) && recorded.has(values[index]))) {\n entryValues.push(values[index]);\n numbers.push(symbols.numbers[index]);\n texts.push(symbols.texts[index]);\n }\n }\n\n return Object.freeze({\n field,\n values: Object.freeze(entryValues),\n numbers: Object.freeze(numbers),\n texts: Object.freeze(texts),\n });\n}\n\n/**\n * Both halves of every symbol of a field: the decoded arrays themselves, frozen, since nothing else\n * holds them once the read resolves.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @return {SymbolHalves} The halves, null for a filtered-out symbol.\n */\nfunction symbolHalves(symbols) {\n return Object.freeze({texts: Object.freeze(symbols.texts), numbers: Object.freeze(symbols.numbers)});\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {asDual} from './util/cellRules.js';\nimport {readerOptionsFrom, windowFrom} from './util/readOptions.js';\n\n/**\n * @typedef {import('./util/resolveSymbols.js').SymbolHalves} SymbolHalves\n */\n\n/**\n * The number a symbol's value stands for, or NaN.\n *\n * A number is itself and a dual is its number. A string is NaN, unless the read kept its halves and\n * the symbol has a number - a dual read as its text, such as a date read with `{duals: 'text'}`, whose\n * serial is still the value Qlik sums and compares by.\n *\n * @param {any} value The symbol's value.\n * @param {number|null} number The symbol's stored number, from its halves, or null.\n * @return {number} The number.\n */\nfunction numberOf(value, number) {\n if (typeof value === 'number') {\n return value;\n }\n\n if (typeof value === 'string') {\n return number ?? NaN;\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.number === 'number' ? dual.number : NaN;\n}\n\n/**\n * The text a symbol's value stands for, derived from the value alone.\n *\n * @param {any} value The symbol's value.\n * @return {string|null} A string itself, a dual's text, or null.\n */\nfunction textOf(value) {\n if (typeof value === 'string') {\n return value;\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.text === 'string' ? dual.text : null;\n}\n\n/**\n * One column of a QVD, as the file stores it: a code per row and a dictionary of values.\n *\n * This is the shape the format already has. A QVD does not store a value per cell; it stores a\n * table of distinct symbols per field and an array of indices into it. Keeping that shape is\n * what makes a column cheap - four bytes per row, plus one entry per *distinct* value - and it\n * is why none of the questions that dog a per-row typed array arise here:\n *\n * - A mixed column needs no decision, because nothing per row is typed. On the bundled\n * `chicago_taxi_rides_2016_01` fixture, read with the default options, **exactly one of its 20\n * columns is strictly numeric** - `trip_start_timestamp`, whose timestamps read as numbers - and\n * two are 100% strings: `pickup_census_tract`, every cell of it blank, and `payment_type`.\n * `dropoff_census_tract` is 43.3% empty strings, and a `Float64Array` of values would put NaN in\n * all of those rows and erase Qlik's distinction between a blank and a number.\n * - NULL is a property of the position, not of the value: `codes[row] < 0`. No sentinel is\n * invented, so no sentinel can collide with real data.\n * - An all-null column, a single-valued column and a zero-row column are the same code path.\n */\nexport class QvdColumn {\n /**\n * @param {string} name The field name.\n * @param {Int32Array} codes One stored index per row, bias applied. Negative means NULL.\n * @param {Array<any>} symbols The field's distinct values, indexed by code.\n * @param {SymbolHalves|null} [halves=null] Both halves of each symbol, aligned with `symbols`, for a\n * field whose values do not show them all - a dual read as one half, a string read as a number.\n * Without them, the halves are derived from the values: a string is its own text, a dual has its\n * own, and a number has none.\n */\n constructor(name, codes, symbols, halves = null) {\n this._name = name;\n this._codes = codes;\n this._symbols = symbols;\n this._halves = halves;\n\n Object.freeze(this);\n }\n\n /** @return {string} The field name. */\n get name() {\n return this._name;\n }\n\n /** @return {number} Rows in the column. */\n get length() {\n return this._codes.length;\n }\n\n /**\n * The stored index of each row. Negative means NULL.\n *\n * The table's own array, not a copy - it is the thing that makes this cheap, and copying it\n * per call would defeat the point. Treat it as read-only.\n *\n * @return {Int32Array} One code per row.\n */\n get codes() {\n return this._codes;\n }\n\n /**\n * The field's distinct values, indexed by the codes.\n *\n * One entry per distinct value, not per row: a few thousand entries for a column of millions.\n *\n * A windowed read that filters the symbol table decodes only the symbols its rows use. Every other\n * entry is `undefined` - not `null`, which a QVD never stores as a symbol - and no code refers to it.\n *\n * @return {ReadonlyArray<any>} The dictionary.\n */\n get symbols() {\n return this._symbols;\n }\n\n /**\n * The value of one row.\n *\n * @param {number} row The row index.\n * @return {any} The value, or null where the file stores NULL.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n at(row) {\n if (!Number.isInteger(row) || row < 0 || row >= this._codes.length) {\n throw new QvdValidationError('Row index out of bounds', {\n column: this._name,\n row,\n length: this._codes.length,\n });\n }\n\n const code = this._codes[row];\n\n return code < 0 ? null : this._symbols[code];\n }\n\n /**\n * The text of one row: the text Qlik displays for its value.\n *\n * A string is its own text and a dual has its own. A value read as one half of a symbol - a date\n * read as its serial, a string read as a number - has the text the file stores for it, and a pure\n * number has none.\n *\n * @param {number} row The row index.\n * @return {string|null} The text, or null for NULL and for a number with no text.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n textAt(row) {\n if (!Number.isInteger(row) || row < 0 || row >= this._codes.length) {\n throw new QvdValidationError('Row index out of bounds', {\n column: this._name,\n row,\n length: this._codes.length,\n });\n }\n\n const code = this._codes[row];\n\n if (code < 0) {\n return null;\n }\n\n return this._halves !== null ? (this._halves.texts[code] ?? null) : textOf(this._symbols[code]);\n }\n\n /**\n * The text of each distinct value, indexed by the codes, as `textAt` gives it per row.\n *\n * @return {ReadonlyArray<string|null>} One text per symbol, null where a symbol has none.\n */\n symbolTexts() {\n if (this._halves !== null) {\n return this._halves.texts;\n }\n\n return Object.freeze(this._symbols.map(textOf));\n }\n\n /**\n * Iterates the column's values without materialising it.\n *\n * @return {Iterator<any>} An iterator over the values, NULLs included as null.\n */\n [Symbol.iterator]() {\n const codes = this._codes;\n const symbols = this._symbols;\n let row = 0;\n\n return {\n next() {\n if (row >= codes.length) {\n return {done: true, value: undefined};\n }\n\n const code = codes[row++];\n\n return {done: false, value: code < 0 ? null : symbols[code]};\n },\n };\n }\n\n /**\n * The column as a plain array of values, one per row.\n *\n * Lossless, and cell-for-cell what `QvdDataFrame.data[row][column]` would hold. The caller\n * owns the result; the table keeps no reference to it, so two calls return two arrays.\n *\n * @return {Array<any>} One value per row.\n */\n toArray() {\n const out = new Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n out[row] = code < 0 ? null : this._symbols[code];\n }\n\n return out;\n }\n\n /**\n * The dictionary as numbers, for scanning without materialising the column.\n *\n * One entry per *distinct* value, not per row - 17 KB for a column of 1.7 million rows with\n * 2,188 symbols - so this is the cheap conversion, where `toFloat64Array()` is the expensive\n * one. Non-numeric symbols become NaN, which is safe here in a way it is not per row: the\n * codes still distinguish NULL, and a caller that wants the blank back still has `symbols`.\n *\n * A dual is its number, however it was read: a `QvdDual` gives `.number`, and a date read with\n * `{duals: 'text'}` gives the serial the file stores for it, not NaN.\n *\n * Scanning `codes` against this is the fastest way to read a column, because both sides are\n * contiguous typed arrays and the dictionary fits in cache:\n *\n * ```js\n * const codes = column.codes;\n * const values = column.numericSymbols();\n * let total = 0;\n * for (let row = 0; row < codes.length; row++) {\n * const code = codes[row];\n * if (code >= 0) {\n * const value = values[code];\n * if (!Number.isNaN(value)) total += value;\n * }\n * }\n * ```\n *\n * @return {Float64Array} One number per distinct symbol, NaN where the symbol is not a number.\n */\n numericSymbols() {\n const out = new Float64Array(this._symbols.length);\n\n for (let index = 0; index < this._symbols.length; index++) {\n out[index] = numberOf(this._symbols[index], this._halves?.numbers[index] ?? null);\n }\n\n return out;\n }\n\n /**\n * The column as a `Float64Array`.\n *\n * Named for what it costs rather than offered as *the* representation, because it is lossy\n * and on real data it is lossy often: it cannot distinguish a blank from a number, and the\n * bundled taxi fixture has a column that is 43% blank. It therefore refuses by default\n * rather than quietly writing NaN over two fifths of a column.\n *\n * @param {Object} [options] Conversion options.\n * @param {'throw'|'nan'} [options.onNonNumeric='throw'] What to do with a value that is not a\n * number - including NULL. `'throw'` refuses and names the offending row; `'nan'` writes\n * NaN, which is the right choice only when the caller knows the column is numeric. A dual is a\n * number here, as it is to `numericSymbols`.\n * @return {Float64Array} One number per row.\n * @throws {QvdValidationError} If a value is not a number and `onNonNumeric` is `'throw'`.\n */\n toFloat64Array(options = {}) {\n const {onNonNumeric = 'throw'} = options;\n\n if (onNonNumeric !== 'throw' && onNonNumeric !== 'nan') {\n throw new QvdValidationError('onNonNumeric must be \"throw\" or \"nan\"', {\n column: this._name,\n provided: onNonNumeric,\n });\n }\n\n const out = new Float64Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n const value = code < 0 ? null : this._symbols[code];\n\n if (typeof value === 'number') {\n out[row] = value;\n continue;\n }\n\n // A dual's number, from the value or from the halves the read kept. NULL has neither.\n const number = value === null ? NaN : numberOf(value, this._halves?.numbers[code] ?? null);\n\n if (!Number.isNaN(number)) {\n out[row] = number;\n continue;\n }\n\n if (onNonNumeric === 'throw') {\n throw new QvdValidationError('Column holds a value that is not a number', {\n column: this._name,\n row,\n value,\n type: value === null ? 'null' : typeof value,\n hint: 'Pass {onNonNumeric: \"nan\"} to write NaN instead, or use toArray() to keep the value.',\n });\n }\n\n out[row] = NaN;\n }\n\n return out;\n }\n}\n\n/**\n * A QVD read as columns rather than as rows.\n *\n * The same file, the same decoder and the same symbol resolution as `QvdDataFrame.fromQvd` -\n * it simply stops before building rows, and keeps what the decoder already produced. Measured\n * on `__tests__/data/chicago_taxi_rides/chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows x 20\n * columns, as `heapUsed + arrayBuffers` either side of a forced collection with each read in a\n * process of its own - `benchmarks/capture-baseline.js`, on 1.0.1:\n *\n * | | retained | of it on the V8 heap | bytes/cell |\n * | --- | --- | --- | --- |\n * | `QvdDataFrame.fromQvd()` | 352 MiB | 352 MiB | 10.83 |\n * | `QvdColumnTable.fromQvd()` | 133 MiB | 3 MiB | 4.08 |\n *\n * Nearly all of a columnar read is its codes, an `Int32Array` per field, whose storage lives\n * outside the V8 heap - which is why the heap alone once put it at a fraction of this.\n *\n * It is not a data frame and does not become one. Offering a conversion would let a caller hold\n * both representations at once, which is the one configuration in which this costs more than it\n * saves. Re-reading a file as rows costs what reading it as rows always cost; there is no\n * saving to protect by avoiding that.\n */\nexport class QvdColumnTable {\n /**\n * @param {Object} decoded What the reader decoded.\n * @param {Array<string>} decoded.columns Field names, in file order.\n * @param {Array<Int32Array>} decoded.codesByField One code array per field.\n * @param {Array<Array<any>>} decoded.symbolsByField One dictionary per field.\n * @param {Array<SymbolHalves|null>} [decoded.halvesByField] Both halves of each symbol, per field,\n * or null for a field whose values show them.\n * @param {number} decoded.rowCount Rows decoded.\n * @param {any} decoded.metadata The raw QvdTableHeader.\n * @param {import('./util/storedSymbols.js').StoredSymbols|null} [decoded.storedSymbols] The\n * stored-symbol record, as a data frame of the same read carries it.\n * @param {any} decoded.loadStats Statistics about the read.\n */\n constructor({columns, codesByField, symbolsByField, halvesByField, rowCount, metadata, storedSymbols, loadStats}) {\n this._columns = columns;\n this._codesByField = codesByField;\n this._symbolsByField = symbolsByField;\n this._halvesByField = halvesByField ?? null;\n this._rowCount = rowCount;\n this._metadata = metadata;\n this._storedSymbols = storedSymbols ?? null;\n this._loadStats = loadStats;\n }\n\n /**\n * Reads a QVD file as columns.\n *\n * Takes the same options as `QvdDataFrame.fromQvd`, with the same meanings - one option\n * vocabulary for both read paths, because they are two answers about the same file rather than\n * two features. `{offset, limit}` is how a caller pages through a file columnwise; there is no\n * columnar `iterate()` because there is nothing for it to bound - a columnar read materialises\n * no rows, which is the memory chunking exists to cap.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Loading options, with the same meanings they have on `fromQvd`.\n * @param {number|null} [options.maxRows] Rows to decode. The older name for `limit`.\n * @param {number|null} [options.limit] Rows to decode, counting from `offset`.\n * @param {number} [options.offset] File row to start at.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear. Unselected fields have their symbols skipped entirely.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol's value is: its\n * number, its text, or a frozen `QvdDual` holding both. Whichever it is, `column.textAt` gives the\n * text and `numericSymbols` the number. Anything else throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a value that would be a string is a\n * number when its text is not blank and `Number(text)` is finite - a string symbol as\n * `Number(text)`, a dual read as text as its stored number. `column.textAt` still gives the text.\n * Anything but a boolean throws.\n * @param {Function} [options.onProgress] Progress callback, `{stage, current, total, percent}`.\n * @param {AbortSignal} [options.signal] Cancels the read.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor] Fraction of the memory budget a load may use.\n * @param {number} [options.symbolFilteringThreshold] Symbol table size above which a limited\n * read switches to two-pass filtering.\n * @return {Promise<QvdColumnTable>} The file, as columns.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n const reader = new QvdFileReader(path, {\n ...readerOptionsFrom(options),\n\n // This read builds no rows, so the memory guard must not charge it for them. A columnar\n // read of the 38MB taxi fixture completes in a 15MB heap; charged the row cost it was\n // refused below a 2GB one.\n materialisesRows: false,\n });\n\n return await reader.loadColumnar(windowFrom(options));\n }\n\n /** @return {Array<string>} Field names, in file order. */\n get columns() {\n return this._columns;\n }\n\n /** @return {number} Rows decoded. */\n get rowCount() {\n return this._rowCount;\n }\n\n /** @return {Array<number>} `[rows, columns]`, as on a data frame. */\n get shape() {\n return [this._rowCount, this._columns.length];\n }\n\n /** @return {any} The raw `QvdTableHeader`. */\n get metadata() {\n return this._metadata;\n }\n\n /** @return {any} Statistics about the read. */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * The stored-symbol record of the read, as `QvdDataFrame.storedSymbols` describes it.\n *\n * @return {import('./util/storedSymbols.js').StoredSymbols|null} The record, or null.\n */\n get storedSymbols() {\n return this._storedSymbols;\n }\n\n /**\n * One column.\n *\n * @param {string} name The field name.\n * @return {QvdColumn} The column.\n * @throws {QvdValidationError} If the field is not in this file.\n */\n column(name) {\n const index = this._columns.indexOf(name);\n\n if (index === -1) {\n throw new QvdValidationError(`Column '${name}' does not exist`, {\n column: name,\n availableColumns: this._columns,\n });\n }\n\n return new QvdColumn(\n name,\n this._codesByField[index],\n this._symbolsByField[index],\n this._halvesByField?.[index] ?? null,\n );\n }\n}\n","// @ts-check\n\nimport xml from 'xml2js';\n// Node's assert, used only for invariants a bug in this library would violate - \"this private\n// method ran after the one that fills the field it reads\". Never for input: everything a caller\n// can get wrong throws a QvdError with a context object instead.\n//\n// #143 read the old Copilot instruction \"use assertions for validation\" as an explanation for\n// these calls. It is not: every one sits after a method that either assigns the field\n// unconditionally or throws, and 3,570 corruption cases across every bundled fixture and every\n// entry point produced no AssertionError. They are checked, and they stay.\nimport assert from 'assert';\nimport {QvdDataFrame} from './QvdDataFrame.js';\nimport {QvdParseError, QvdValidationError, QvdCorruptedError} from './QvdErrors.js';\nimport {checkPath} from './util/validatePath.js';\nimport {openChecked} from './util/openChecked.js';\nimport {closeAfter, rethrowAsIoError} from './util/ioErrors.js';\nimport {decodeIndexColumn} from './util/bitUtils.js';\nimport {checkMemory, getMemoryBudget, validateMemoryAvailability, warnLargeSymbolTable} from './util/memoryUtils.js';\nimport {\n headerInteger,\n validateBitFields,\n validateHeaderStructure,\n validateSymbolAreas,\n validateSymbolTableSize,\n validateSymbolTableSizeEarly,\n validateFieldMetadata,\n validateIndexTableMetadata,\n validateFieldBitMetadata,\n validateRecordCount,\n validateRecordSize,\n} from './util/validationUtils.js';\nimport {countFieldSymbols, parseFieldSymbols} from './util/symbolParser.js';\nimport {\n normaliseCoerceNumericStrings,\n normaliseDuals,\n normaliseWindow,\n resolveWindow,\n selectFields,\n requireChunkSize,\n} from './util/readOptions.js';\nimport {resolveFieldSymbols} from './util/resolveSymbols.js';\nimport {attachStoredSymbols, trustStoredSymbols} from './util/storedSymbols.js';\n\n/**\n * @typedef {import('./util/readOptions.js').QvdRowWindow} QvdRowWindow\n */\n\n/**\n * Maximum number of bytes searched for the XML header delimiter before giving up.\n * Real QVD headers are a few kilobytes; the largest observed is well under 100KB.\n */\nconst MAX_HEADER_SIZE = 16 * 1024 * 1024;\n\n/**\n * Maximum length of a single fs.read call. Node's fs.read binding requires the length to fit\n * in an Int32: a larger value aborts the process via a C++ assertion instead of throwing.\n */\nconst READ_CHUNK_SIZE = 512 * 1024 * 1024;\n\n/**\n * Rows the two-pass symbol analysis decodes at a time.\n *\n * The pass collects the *set* of stored indices a window references, and a set is the same\n * whether it is built in one pass or in slices - so this bounds the scratch column at 256KB\n * instead of four bytes per row of the window. It is a working-set size, not a correctness\n * parameter: any value gives the same answer.\n */\nconst ANALYSIS_SLICE_ROWS = 65536;\n\n/**\n * Bytes of records read from the file at a time.\n *\n * The index table is read in slices of whole records, into one buffer reused for every slice, and each\n * slice is decoded before the next is read. A read used to hold the file in one buffer - the whole of it,\n * or the header, the symbol table and every record of the window - so what it needed grew with the file:\n * `iterate()` over 2.24 GB held 2.24 GB from its first chunk on (#122). A slice bounds that at this size,\n * whatever the file's, and is large enough that the number of reads it takes costs nothing next to\n * decoding them. A record is at most 1 MB, so a slice always holds at least sixteen.\n *\n * The default of the reader's `sliceBytes` option, which only a test changes.\n */\nconst SLICE_BYTES = 16 * 1024 * 1024;\n\n/**\n * Distinct indices the symbol-usage pass keeps for one field before it counts the field's symbols.\n *\n * Below this it trusts the bound the field's bytes give, which costs nothing. Past it the set is large\n * enough to matter, and that bound says too little: a field holding one 50 MB string still allows 25\n * million. So the field's symbols are counted, one walk of its area, and the set is held to them. A\n * valid read that needs more than this many of one field's symbols pays that walk once. One that needs\n * fewer, which is what the two-pass path is for, never does.\n */\nconst COUNT_SYMBOLS_PAST = 65536;\n\n/**\n * Reads a file from its start, a chunk at a time, through a handle already open.\n *\n * The header used to be scanned with `fs.createReadStream(path)`, which opened the file a second time\n * by name - and the body was read by a third open, of the same name. Each was another resolution of\n * a path that can change between them: #247 was a symlink swapped in after the containment check, and\n * every one of those opens followed it. Reading the header through the one handle the read holds keeps\n * the header, the symbol table and the index table in the same file, and that file the one the check\n * approved.\n *\n * Positional reads, so the handle's own file position never moves and a later `readFile()` on it\n * still starts at the beginning. A read can return fewer bytes than it was asked for, and the chunk\n * is then shorter; nothing downstream assumes a size.\n *\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {number} chunkSize The most to read at a time.\n * @param {(error: unknown) => never} failed The read's `rethrowAsIoError` handler.\n * @yield {Buffer} The file's bytes, in order, until its end.\n */\nasync function* chunksFrom(handle, chunkSize, failed) {\n let position = 0;\n\n for (;;) {\n const buffer = Buffer.alloc(chunkSize);\n const {bytesRead} = await handle.read(buffer, 0, chunkSize, position).catch(failed);\n\n if (bytesRead === 0) {\n return;\n }\n\n // What arrived, copied when it is short, so a short last chunk does not pin a whole chunk's buffer.\n yield bytesRead === chunkSize ? buffer : Buffer.from(buffer.subarray(0, bytesRead));\n position += bytesRead;\n }\n}\n\n/**\n * Parses a QVD's XML header, reporting a header that is not XML as a `QvdParseError`.\n *\n * xml2js rejects malformed XML with its SAX parser's bare `Error` - \"Unexpected close tag\", \"Non-whitespace\n * before first tag.\" - which names neither the file nor what was being read, and which escapes every\n * `catch (error) { if (error instanceof QvdError) ... }` a caller has written around a read. It is where\n * most damage to a header ends up: 75 of 120 random byte flips inside one, in the September 2026 audit.\n * Both places that parse a header go through this, so the two cannot report the same header differently.\n *\n * Well-formed XML that is not a QVD header parses, and is `validateHeaderStructure`'s to refuse.\n *\n * Note: xml2js (via sax-js) does not support external entity resolution by default, providing inherent\n * protection against XXE attacks.\n *\n * @param {string} text The header, delimiter included.\n * @param {string} file The file, for the error.\n * @param {string} stage Stage name recorded in the error context.\n * @return {Promise<any>} The parsed header.\n * @throws {QvdParseError} If the text is not well-formed XML, or parses to nothing.\n */\nasync function parseHeaderXml(text, file, stage) {\n let parsed;\n\n try {\n parsed = await xml.parseStringPromise(text, {explicitArray: false});\n } catch (error) {\n throw new QvdParseError(\n 'The XML header could not be parsed.',\n {\n // The first line of the parser's message. The rest is the line and column it stopped at, which\n // stay on `cause`.\n reason: String(/** @type {any} */ (error)?.message ?? error).split('\\n')[0],\n file,\n stage,\n },\n {cause: error},\n );\n }\n\n if (!parsed) {\n throw new QvdParseError('The XML header could not be parsed.', {file, stage});\n }\n\n return parsed;\n}\n\n/**\n * Parses a QVD file and loads it into memory.\n */\n/**\n * Bytes of symbols a read of these fields will read: their areas, not the table those areas sit in.\n *\n * A read of one field of a file whose other fields hold gigabytes reads that field's area alone, so\n * sizing it by the table refused reads that fit a hundred times over - the refusal #122 is about. The\n * whole table stands in where the header's areas cannot be used, or claim more than the table holds,\n * because then this is a guess and the guess should be the large one.\n *\n * Shared by the read and by the pre-flight check, so that what the check approves is what the read is\n * then measured against. Two copies of this arithmetic would be two answers about one file.\n *\n * @param {Array<any>} selected The fields the read selects, from the header.\n * @param {number} symbolTableLength The symbol table's declared length.\n * @return {number} Bytes.\n */\nfunction symbolBytesOf(selected, symbolTableLength) {\n const areaBytes = selected.map((/** @type {any} */ field) => headerInteger(field['Length']));\n\n return areaBytes.every((bytes) => Number.isSafeInteger(bytes) && bytes >= 0)\n ? Math.min(\n symbolTableLength,\n areaBytes.reduce((sum, bytes) => sum + bytes, 0),\n )\n : symbolTableLength;\n}\n\n/**\n * How many times a read passes over the records it covers.\n *\n * Two where the symbol-usage pass is still ahead of it: that pass reads the window's records to find\n * which symbols its rows use, and the decode then reads them again. One otherwise. It is the read's\n * I/O rather than its memory - the records go through one buffer either way - and it is reported so\n * that `estimate.readBytes` describes the file access a read really makes.\n *\n * @param {boolean} analysisAhead Whether the symbol-usage pass has still to run.\n * @return {number} Passes over the records.\n */\nfunction readPasses(analysisAhead) {\n return analysisAhead ? 2 : 1;\n}\n\n/**\n * Refuses an `onProgress` or `signal` that is not one, in the vocabulary the options use.\n *\n * Shared because the pair arrives by two doors: the constructor, for a reader built for one read, and\n * `observeNextRead`, for a `QvdFile` page that watches its own. One set of rules, so a page cannot be\n * watched by something a read would have refused.\n *\n * @param {any} onProgress The progress callback, or undefined.\n * @param {any} signal The abort signal, or undefined.\n * @param {string} path The file, for the error.\n * @return {void}\n * @throws {QvdValidationError} If either is present and not of its type.\n */\nfunction validateWatchers(onProgress, signal, path) {\n if (onProgress !== undefined && typeof onProgress !== 'function') {\n throw new QvdValidationError('onProgress must be a function', {\n provided: onProgress,\n type: typeof onProgress,\n reason: 'option',\n option: 'onProgress',\n file: path,\n });\n }\n\n // Checked here rather than at the first use, so a caller who passes something signal-shaped finds out\n // before the file is opened instead of discovering that cancellation silently did nothing.\n // `throwIfAborted` is the whole contract this reader needs from it.\n if (signal !== undefined && (typeof signal !== 'object' || signal === null || typeof signal.aborted !== 'boolean')) {\n throw new QvdValidationError('signal must be an AbortSignal', {\n provided: signal,\n type: typeof signal,\n reason: 'option',\n option: 'signal',\n file: path,\n });\n }\n}\n\nexport class QvdFileReader {\n /**\n * Constructs a new QVD file parser.\n *\n * @param {string} filePath The path to the QVD file to load.\n * @param {Object} [options={}] Options for the reader.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction (0.0-1.0) of the memory budget a\n * load may use. The budget is the smaller of the V8 heap limit and any container memory limit;\n * what the OS reports as available is recorded for diagnostics and deliberately not allowed to\n * bind - see `getMemoryBudget`. Default is 0.8. **Zero disables the memory\n * check entirely**, which is the escape hatch for runtimes whose limits cannot be measured -\n * Bun reports its current heap as its heap limit - and for callers who would rather manage\n * memory themselves than trust the estimate.\n * @param {boolean} [options.materialisesRows=true] Whether this read will build row arrays.\n * False for a columnar read, whose memory is TypedArray backing stores outside the V8 heap\n * and which must not be charged the row cost.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes,\n * above which a lazy load switches to the two-pass filtering path. The default of 50MB is\n * the point where the extra analysis pass pays for itself; lower it to use filtering on\n * smaller files, raise it to keep the simpler single-pass read for longer.\n * @param {number} [options.sliceBytes=16777216] The most bytes of records a read holds at a time. An\n * option rather than a constant for the reason `symbolFilteringThreshold` is one: so that a test can\n * cross the boundaries between slices in a small file. There is no other reason to change it, and it\n * is not one of the options a read through `QvdDataFrame` or `QvdColumnTable` passes on.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear. Null reads every field, in file order. An unknown or repeated name is refused.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol - a number with the\n * text Qlik displays for it, such as a date - reads as. `'number'` gives its number, which is the\n * value Qlik sums, sorts and compares by; `'text'` gives its text; `'both'` gives a frozen\n * `QvdDual` holding both halves, shared by every row that holds the symbol. Under `'number'` and\n * `'text'` the half a cell does not show is kept in the frame's `storedSymbols`, so a write stores\n * the dual again. An int, a double, a string and NULL read the same in every mode. Any other value\n * throws a `QvdValidationError`.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite: a string symbol in\n * every `duals` mode, as `Number(text)`, and a dual's text under `duals: 'text'`, as the number the\n * dual stores. The text is kept in the frame's `storedSymbols`, so a write stores the string or the\n * dual again. Anything but a boolean, `undefined` or null throws a `QvdValidationError`.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}` as the\n * read proceeds - the same shape `QvdFileWriter` emits.\n * @param {AbortSignal} [options.signal] Cancels the read. When it is aborted the read throws\n * `signal.reason`, exactly as `signal.throwIfAborted()` does.\n */\n constructor(filePath, options = {}) {\n const {\n allowedDir,\n memorySafetyFactor = 0.8,\n symbolFilteringThreshold = 50 * 1024 * 1024,\n sliceBytes = SLICE_BYTES,\n materialisesRows = true,\n fields = null,\n duals,\n coerceNumericStrings,\n onProgress,\n signal,\n } = options;\n this._materialisesRows = materialisesRows;\n const checked = checkPath(filePath, allowedDir);\n this._path = checked.path;\n /**\n * The allowed directory, resolved. Kept because the path is checked again immediately before it is\n * opened - see `_readData` - and that check has to be made against the directory this one was,\n * whatever the working directory has become since.\n */\n this._allowedDir = checked.base;\n /** What a dual symbol reads as. Checked here, so a bad value fails before the file is opened. */\n this._duals = normaliseDuals(duals, this._path);\n /**\n * Whether a cell that would be a string reads as a number when its text is a finite number. Off\n * unless asked for; on, the text is recorded in the frame's `storedSymbols`, so a write stores the\n * string or the dual it was read from. Checked here, like `duals`, before the file is opened.\n */\n this._coerceNumericStrings = normaliseCoerceNumericStrings(coerceNumericStrings, this._path);\n this._memorySafetyFactor = memorySafetyFactor;\n this._symbolFilteringThreshold = symbolFilteringThreshold;\n\n if (!Number.isSafeInteger(sliceBytes) || sliceBytes <= 0) {\n throw new QvdValidationError('sliceBytes must be a positive integer', {\n provided: sliceBytes,\n type: typeof sliceBytes,\n file: this._path,\n });\n }\n\n /** The most bytes of records a read holds at a time - see `_forEachSlice`. */\n this._sliceBytes = sliceBytes;\n\n validateWatchers(onProgress, signal, this._path);\n\n /** @type {Array<string>|null} */\n this._requestedFields = fields === undefined ? null : fields;\n this._onProgress = onProgress;\n this._signal = signal;\n\n /**\n * The XML header, delimiter included. The rest of the file is never held whole: the symbol table and\n * the records are read from `_handle` as they are parsed.\n *\n * @type {Buffer|null}\n */\n this._headerBuffer = null;\n /**\n * The file, open for as long as a read of rows needs it - from its header to its last record, or for\n * `iterateRows` to its last chunk - and closed by `_closeFile`. Null between reads.\n *\n * @type {import('fs/promises').FileHandle|null}\n */\n this._handle = null;\n /** The open read's `rethrowAsIoError` handler. @type {((error: unknown) => never)|null} */\n this._failed = null;\n /**\n * Whether a read is under way on this reader, from its first line to the close of its file. See\n * `_startRead`.\n */\n this._reading = false;\n /**\n * Where the selected fields' symbols are, and the bytes of those read so far: one entry per range of the\n * symbol table this read reads, dropped as each is parsed, or when the read ends before that. Null\n * between reads, and until the header says where the areas are. See `_symbolAreaPlan`.\n *\n * @type {{ranges: Array<{start: number, end: number, fields: number, buffer: Buffer|null}>,\n * byField: Map<any, {range: any, start: number, end: number}>}|null}\n */\n this._symbolAreas = null;\n\n /**\n * Fields this reader has decoded, by name, when it is paging - see `beginPaging`.\n *\n * Null unless a caller asked for it, because it is the one piece of reader state that deliberately\n * outlives a read. A `QvdFile` turns it on: its pages are reads of one file whose symbols do not\n * change between them, and decoding them is 72% of a page.\n */\n this._symbolCache = null;\n\n /**\n * The header the cache was decoded from, so that a file replaced at the same path between pages is\n * not answered from the old one's values.\n */\n this._cachedFor = null;\n this._headerOffset = null;\n this._symbolTableOffset = null;\n this._indexTableOffset = null;\n this._header = null;\n /**\n * Every field header in the file, in file order, and the caller's selection of them in the\n * order the result should carry. Both are set by `_parseHeader` and null until it has run.\n *\n * One derivation feeds the symbol table, the decoded columns and `columns`, which are three\n * arrays indexed by the same position. Deriving the selection separately at each of those\n * sites - which is what this replaced - meant three answers that had to agree by inspection\n * rather than by construction.\n *\n * @type {Array<any>|null}\n */\n this._allFields = null;\n /** @type {Array<any>|null} */\n this._selectedFields = null;\n /**\n * Whether every field's bit metadata has been validated. Header data, so it is checked once per\n * header: `_parseHeader` clears it whenever it reads one.\n */\n this._fieldBitMetadataValidated = false;\n /** @type {Array<import('./util/symbolParser.js').FieldSymbols>|null} Each selected field's decoded symbols. */\n this._symbolTable = null;\n /**\n * Stored symbol indices, one Int32Array per field rather than one array per row.\n *\n * Column-major because that is what lets the decoder hoist a field's bit offset, width and\n * bias out of the row loop and write straight into a typed array - no allocation per row or\n * per cell. Renamed from `_indexTable` deliberately: the shape changed, and a reader of this\n * code should not have to discover that from the subscripts.\n *\n * @type {Array<Int32Array>|null}\n */\n this._indexColumns = null;\n\n /** Rows actually decoded into `_indexColumns`. @type {number} */\n this._rowsDecoded = 0;\n /** @type {number|null} */\n this._fileSize = null;\n\n /** What the filesystem says this file is, for the cache's fingerprint. @type {string|null} */\n this._fileIdentity = null;\n /** Whether the header's declared extent fits inside the file. False until _readData says so. */\n this._headerMatchesFile = false;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * The same shape `QvdFileWriter._emitProgress` emits, deliberately: a caller who has written a\n * progress bar for a write should not have to write a second one for a read. The stage names\n * differ because the stages differ, but `symbol-table` and `index-table` mean the same thing on\n * both sides.\n *\n * @param {string} stage The current stage of the read.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n * @private\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n\n this._onProgress({stage, current, total, percent});\n }\n }\n\n /**\n * Throws if the caller has cancelled the read.\n *\n * Throws `signal.reason` - a `DOMException` named `AbortError` unless the caller aborted with a\n * reason of their own. That is what `AbortSignal` means everywhere else in Node, and inventing\n * a `QvdAbortError` here would make this library's cancellation the one a caller has to special\n * case.\n *\n * @private\n */\n _throwIfAborted() {\n if (this._signal) {\n this._signal.throwIfAborted();\n }\n }\n\n /**\n * Opens the file and reads its header, and for a read of rows checks that the read can be made.\n *\n * Nothing past the header is read here. The selected fields' symbols and the records are read by position\n * as they are parsed - see `_symbolAreaOf` and `_forEachSlice` - so no read holds the file in one buffer\n * (#122). A read of rows therefore leaves the file open, and whatever started the read closes it with\n * `_closeFile` once the last record it needs is decoded; a header-only read closes it here.\n *\n * A windowed read - anything with `offset`, `limit` or `maxRows` - reads the header, the symbols of the\n * fields it selects, and the window's records, and no byte between. Measured on\n * `chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows over 20 fields: the last thousand rows take 19 ms\n * against 636 ms for the whole file. A selected field's area is read in full whatever the window,\n * because a stored index in any row can address any of that field's symbols; the areas of the fields\n * `fields` leaves out are not read at all. So a window's gain scales with how much of the file is\n * rows: on a file whose bytes are mostly distinct values of the fields it reads there is very little\n * to save, which is what `symbolFilteringThreshold` and the two-pass path exist for.\n *\n * All of it goes through one handle, opened once, on the file the containment check approved. See\n * `chunksFrom` and `openChecked` for why a read no longer opens the path more than once.\n *\n * @param {QvdRowWindow} window The rows to read.\n * @param {boolean} [headerOnly=false] Stop once the XML header has been read, and close the file. This\n * is the metadata-only path: the header is a few kilobytes whatever the file's size, so reading a\n * schema costs the same for a 40MB file as for a 40GB one.\n * @param {{rows: number, perChunk: number}|null} [liveRows=null] Rows held at one instant when\n * that is fewer than the window covers - see `_prepare`.\n * @private\n */\n async _readData(window = {offset: 0, limit: null}, headerOnly = false, liveRows = null) {\n assert(this._reading, 'A read opens the QVD file only once it has started, through _startRead.');\n\n // A read begins by forgetting the one before it. A reader is reusable and the file at its path can have\n // changed, so a read that failed part-way used to leave the last successful read's symbols, codes and\n // row count on the reader, describing a file it was no longer reading. Cleared as the read starts\n // rather than when its file is closed, so that what a finished read parsed is still there to be looked\n // at - which is how the projection tests check that a read parsed one field and not every field.\n this._symbolTable = null;\n this._indexColumns = null;\n this._rowsDecoded = 0;\n\n this._throwIfAborted();\n this._emitProgress('read', 0, 1);\n\n // Every file-system call below goes through this, so a missing or unreadable file - or on Windows\n // one another process has locked - is a QvdIOError carrying the system code rather than Node's bare\n // error.\n const failed = rethrowAsIoError(this._path, 'read');\n\n // Checked again here, immediately before the open, rather than trusting the check the constructor\n // made: the open is held to what this check approved, and the nearer the two are the less there is\n // to hold. One open for the whole read, closed by `closeAfter` or `_closeFile`, so a close that fails\n // cannot replace the error the read is already throwing - a truncated file stays a QvdCorruptedError\n // rather than turning into a QvdIOError about the close - and is reported when the read succeeded.\n const handle = await openChecked(checkPath(this._path, this._allowedDir), 'read', failed);\n\n if (headerOnly) {\n await closeAfter(handle, failed, () => this._readFrom(handle, window, true, liveRows, failed));\n return;\n }\n\n this._handle = handle;\n this._failed = failed;\n\n try {\n await this._readFrom(handle, window, false, liveRows, failed);\n } catch (error) {\n await this._closeFile(true);\n throw error;\n }\n }\n\n /**\n * Starts a read on this reader, refusing it while another is under way.\n *\n * A read of rows holds the file, and what it has read of it, on the reader until it ends. A second read\n * started meanwhile - `load()` while an iteration is suspended, say - would take over that state and\n * leave the first read's file open. Reads one after another are fine. Called before a read takes charge\n * of closing the file, so that refusing the second read cannot close the first one's.\n *\n * The first thing every read does, and synchronous: the flag is set before the read's first `await`, so\n * two reads started together - `Promise.all([reader.load(), reader.load()])` - cannot both pass. The check\n * used to be of the handle, which is set only once the file has opened, and both did: the second read's\n * handle replaced the first's, which was never closed, and the first read to finish closed the file the\n * other was still reading.\n *\n * @throws {QvdValidationError} If a read is under way.\n * @private\n */\n _startRead() {\n if (this._reading) {\n throw new QvdValidationError('The reader is already reading this file: finish that read first', {\n file: this._path,\n });\n }\n\n this._reading = true;\n }\n\n /**\n * Ends the read `_startRead` began: closes its file, if it still holds one, and lets the next read start.\n *\n * @param {boolean} failing Whether the read is already throwing - see `_closeFile`.\n * @private\n */\n async _endRead(failing) {\n try {\n await this._closeFile(failing);\n } finally {\n this._reading = false;\n }\n }\n\n /**\n * Closes the file a read of rows opened, and drops what it had read of it.\n *\n * The rule `closeAfter` follows: a close that fails is reported only when the read succeeded, so it can\n * never replace the error that says what went wrong. After a successful read it is the only news.\n *\n * @param {boolean} failing Whether the read is already throwing.\n * @private\n */\n async _closeFile(failing) {\n const handle = this._handle;\n const failed = this._failed;\n\n this._handle = null;\n this._failed = null;\n this._symbolAreas = null;\n\n if (handle === null || failed === null) {\n return;\n }\n\n if (failing) {\n await handle.close().catch(() => {});\n return;\n }\n\n await handle.close().catch(failed);\n }\n\n /**\n * Runs a read, the only one under way on this reader, and closes its file when it ends, however it ends.\n *\n * @template T\n * @param {() => Promise<T>} read The read, from opening the file to its last record.\n * @return {Promise<T>} What it returned.\n * @private\n */\n async _closingAfter(read) {\n this._startRead();\n\n let result;\n\n try {\n result = await read();\n } catch (error) {\n await this._endRead(true);\n throw error;\n }\n\n await this._endRead(false);\n\n return result;\n }\n\n /**\n * Reads what `_readData` was asked for, through the handle it opened.\n *\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {QvdRowWindow} window The rows to read.\n * @param {boolean} headerOnly Stop once the XML header has been read.\n * @param {{rows: number, perChunk: number}|null} liveRows Rows held at one instant - see `_prepare`.\n * @param {(error: unknown) => never} failed The read's `rethrowAsIoError` handler.\n * @private\n */\n async _readFrom(handle, window, headerOnly, liveRows, failed) {\n // The header is scanned first on both paths, including a full load that is about to read the\n // whole file anyway. It costs a few kilobytes and it is what lets the memory check run\n // *before* the body is read: otherwise a 1.7GB file is loaded into memory in full and only\n // then refused, which is the opposite of what a safety check is for.\n const HEADER_DELIMITER = '\\r\\n\\0';\n const CHUNK_SIZE = 64 * 1024; // 64KB chunks - balance between memory and I/O efficiency\n\n /** @type {Array<Buffer>} */\n const headerChunks = [];\n let headerBytes = 0;\n /** Last (delimiter length - 1) bytes seen so far, carried across chunk boundaries. */\n let tail = Buffer.alloc(0);\n let headerDelimiterIndex = -1;\n\n // Read chunks until we find the delimiter.\n //\n // Chunks are collected and concatenated once, and each chunk is searched individually\n // (with a small carry-over so a delimiter straddling a chunk boundary is still found).\n // Concatenating the whole accumulated buffer on every chunk and re-scanning it from the\n // start is quadratic: a 200 MB delimiter-less file cost 43 s and 13 GB of memory.\n //\n // A failed read reaches the caller as a QvdIOError through `failed`, and anything else thrown here\n // - the corrupted-file error below, or a bug - passes through as it is. That is not an accident of\n // structure: the stream this used to be caught every error its iterator threw, and a version of\n // that catch once reported a bug with no `code` as a corrupt file.\n for await (const chunk of chunksFrom(handle, CHUNK_SIZE, failed)) {\n // Search the new chunk prefixed by the bytes already seen, so a delimiter spanning a\n // chunk boundary is not missed.\n //\n // The carry is kept in `tail` across iterations rather than read back off the previous\n // chunk, because a chunk may be shorter than the delimiter. Taking min(bytesSoFar, 2)\n // bytes from a 1-byte previous chunk yields only 1 byte, which both misses a delimiter\n // spread over three chunks and leaves the reported offset short by the difference.\n const chunkStart = headerBytes;\n const searchBuffer = tail.length > 0 ? Buffer.concat([tail, chunk]) : chunk;\n const foundInSearch = searchBuffer.indexOf(HEADER_DELIMITER);\n\n headerChunks.push(chunk);\n headerBytes += chunk.length;\n\n if (foundInSearch !== -1) {\n // searchBuffer starts tail.length bytes before this chunk does.\n headerDelimiterIndex = chunkStart - tail.length + foundInSearch;\n break;\n }\n\n // Copy the carry instead of keeping a subarray view, which would pin the whole chunk.\n tail = Buffer.from(searchBuffer.subarray(-(HEADER_DELIMITER.length - 1)));\n\n // Real QVD headers are a few kilobytes. Without a cap, a non-QVD or corrupt file is\n // read to its end before the error below is raised, which is a denial-of-service\n // vector for any service that accepts uploaded files.\n if (headerBytes > MAX_HEADER_SIZE) {\n throw new QvdCorruptedError(\n `The XML header delimiter was not found within the first ${MAX_HEADER_SIZE / (1024 * 1024)}MB of the file.`,\n {\n file: this._path,\n bytesSearched: headerBytes,\n maxHeaderSize: MAX_HEADER_SIZE,\n stage: 'readData',\n },\n );\n }\n }\n\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'readData',\n },\n );\n }\n\n const headerBuffer = Buffer.concat(headerChunks);\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n\n // Parse header to get metadata about symbol and index table locations\n const headerXml = headerBuffer.subarray(0, headerEndIndex).toString();\n const headerObj = await parseHeaderXml(headerXml, this._path, 'readData');\n const headerFields = validateHeaderStructure(headerObj, this._path, 'readData');\n\n const symbolTableOffset = headerEndIndex;\n const symbolTableLength = headerInteger(headerObj['QvdTableHeader']['Offset']);\n const indexTableOffset = symbolTableOffset + symbolTableLength;\n const recordSize = headerInteger(headerObj['QvdTableHeader']['RecordByteSize']);\n const totalRows = headerInteger(headerObj['QvdTableHeader']['NoOfRecords']);\n\n // The file's size bounds every read that follows, whatever the header says - and it is what says\n // whether the header describes this file at all. One `stat`, before the header-only return as well\n // as after it: `readMetadata` does not use the answer, but `checkRead` cannot do its job without\n // it, and a header-only read that skipped the call reported a truncated file as a read too large\n // to fit rather than as a file that is short.\n const {size: fileSize, ino, dev, mtimeMs} = await handle.stat().catch(failed);\n this._fileSize = fileSize;\n\n // What the file is, as the filesystem knows it, for the symbol cache to compare against - see\n // `_fileFingerprint`. The header's own numbers are not enough on their own: `QvdFileWriter` carries\n // `CreateUtcTime` over from the metadata it was given, so a read-modify-write that changes a text to\n // another of the same length rewrites every value while leaving every number this reader can see\n // identical. An atomic write renames a new file into place and changes the inode; an in-place one\n // (`{atomic: false}`) keeps it and moves `mtimeMs`.\n this._fileIdentity = `${dev}:${ino}:${mtimeMs}:${fileSize}`;\n\n // Decided again for this read, and cleared first: it describes the file being read now, and a reader\n // may read again - a file that has changed since, or another read of one that never matched. Left from\n // the read before, it said yes about a file whose numbers this one could not use, and\n // `_parseSymbolTable` gates its memory check on this flag alone. That check then estimated from a\n // `NaN` row count, which refuses nothing, so the structural error still came out of `_planIndexTable`:\n // wrong question, right answer. `_fieldBitMetadataValidated` is cleared per header for the same reason.\n this._headerMatchesFile = false;\n\n // Two conditions, and both exist so that a corrupt file keeps its accurate diagnosis instead of\n // being reported as an out-of-memory problem. The numbers have to be usable at all - a NaN or\n // negative Offset would produce a nonsense estimate - and they have to be consistent with the file\n // on disk. The estimate is computed from NoOfRecords, so a header that overstates it produces an\n // enormous figure: a truncated 3KB file claiming 900 million rows was refused for needing 530GB of\n // RAM, when what it actually needs is to be re-downloaded. Where the file contradicts its own\n // header, the memory check below stands aside and lets the structural checks say what is wrong.\n const headerNumbersUsable = [symbolTableLength, recordSize, totalRows].every(\n (value) => Number.isSafeInteger(value) && value >= 0,\n );\n\n if (headerNumbersUsable) {\n this._headerMatchesFile = headerEndIndex + symbolTableLength + totalRows * recordSize <= fileSize;\n }\n\n if (headerOnly) {\n // The header, and not one byte more. `headerChunks` holds whole 64KB chunks, so the tail\n // of the last one is whatever followed the delimiter; trimming it is what keeps this\n // constant-cost rather than \"the header plus up to 64KB of symbol table\".\n //\n // This returns before the memory check below on purpose. That check sizes the rows a call\n // will materialise, and this call materialises none - running it would let a file too\n // large to load refuse to report its own schema, which is the opposite of the point.\n //\n // _parseHeader runs next and re-derives the offsets from this buffer, exactly as it does\n // on the full path. Nothing downstream of it is reached, because there are no rows.\n this._headerBuffer = headerBuffer.subarray(0, headerEndIndex);\n this._emitProgress('read', 1, 1);\n return;\n }\n\n // A read of rows parses the header from here too, and reads the rest of the file as it goes.\n this._headerBuffer = headerBuffer.subarray(0, headerEndIndex);\n\n // Column count drives the largest term in the memory estimate, because what actually\n // exhausts the heap on a many-row file is one array per row plus one slot per cell - not the\n // symbol table, which for the commonest Qlik shape is tiny.\n //\n // A field selection is checked here, before anything large is read, and the count it produces\n // is what the memory guard is charged for. Both halves matter: an unknown field name costs\n // nothing to discover at this point, and charging a two-column projection for twenty columns\n // would refuse reads that fit ten times over.\n const selected = selectFields(headerFields, this._requestedFields, this._path);\n const columnCount = selected.length;\n // Two figures, because they answer two questions - see `_fieldsReadBy`. What the read will hold sizes\n // the heap; what it will read sizes the buffers it holds while parsing and the I/O it reports.\n const symbolBytes = symbolBytesOf(this._fieldsHeldAfter(selected, headerFields), symbolTableLength);\n const readSymbolBytes = symbolBytesOf(this._fieldsReadBy(selected), symbolTableLength);\n // What letting go of the file would release that this read does not need: the columns an earlier\n // page decoded and this one does not select. A cached column this read *does* select is needed\n // either way, so releasing it is no remedy and it does not count here.\n const retainedBytes = symbolBytesOf(\n this._fieldsHeldAfter(selected, headerFields).slice(selected.length),\n symbolTableLength,\n );\n\n // SAFETY CHECK: enough memory to materialise the rows this call will produce. Runs here,\n // before any large read, so a file too big to hold is refused rather than read and refused.\n // `headerNumbersUsable` and `_headerMatchesFile`, decided above, are what gate it.\n\n // Where the window really lands in this file, clamped to the rows it has.\n const resolved = headerNumbersUsable ? resolveWindow(window, totalRows) : {offset: 0, limit: 0};\n const windowRows = resolved.limit;\n\n if (headerNumbersUsable && this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolBytes,\n windowRows,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n columnCount,\n this._materialisesRows,\n liveRows,\n this._bytesHeld(\n readSymbolBytes,\n windowRows,\n recordSize,\n liveRows,\n this._analysisAhead(window, resolved, totalRows, symbolTableLength),\n symbolBytes - retainedBytes,\n ),\n // What it reads, which is not what it holds - the records go through one buffer and are not\n // kept. Carried so that a refusal's `check` says everything the pre-flight would have said.\n //\n // Twice over where the symbol-usage pass is still ahead of it: that pass reads the window's\n // records to find which symbols the rows use, and the decode then reads them again. Counted\n // once, the figure understated the I/O of exactly the reads that do the most of it.\n readSymbolBytes +\n readPasses(this._analysisAhead(window, resolved, totalRows, symbolTableLength)) * windowRows * recordSize,\n // A paging read keeps whole columns, so the estimate must not discount its symbols as a window's\n // sample of them - see `estimateMemoryUsage`. Under-charging is the direction that ends in a\n // heap-limit abort rather than an error.\n this._symbolCache !== null,\n retainedBytes,\n );\n }\n\n if (window.offset === 0 && window.limit === null) {\n // The whole file, and nothing more to read here: the symbol table and the records are read as\n // they are parsed. They used to be read here with the handle's `readFile()`, which Node caps at\n // 2 GiB, so every whole-file read of a larger QVD failed with its raw `RangeError` (#122).\n //\n // A file shorter than its header claims is found as it is parsed, with the errors a whole-file\n // read has always given: a symbol area past the end of the file is `Symbol data extends beyond\n // buffer`, an index table past it `Index table extends beyond the end of the file`.\n this._emitProgress('read', 1, 1);\n return;\n }\n\n const rowsToLoad = windowRows;\n\n // SAFETY CHECK: Very large symbol tables are still blocked to prevent OOM. Every read that is\n // not a whole-file read reaches here, which is the point at which it still costs nothing to\n // refuse: nothing past the header has been read yet, and the symbol table is read whole\n // whatever the window, because a stored index in any row can address any symbol.\n //\n // This deliberately does NOT distinguish `{offset: n, limit: m}` from `{offset: n}`. An\n // earlier revision of this work exempted the second, on the reasoning that a window bounded\n // only by an offset runs to the end of the file and so should be gated like a full read.\n // Measured on a 16,000-row fixture with a 153MB symbol table at a 288MB heap, that was wrong\n // in the uncatchable direction: `{offset: 15990, limit: 10}` was refused having allocated\n // nothing, at 53MB of RSS, while `{offset: 15990}` - the same ten rows - skipped this check,\n // passed the memory guard (whose symbol term is discounted by sqrt(windowRows/totalRows), so\n // it collapses for a small window), allocated and filled the whole 153MB buffer, and was only\n // then refused by the 50% ceiling in `_parseSymbolTable`. 207MB of RSS to read ten rows, and\n // inside a container sized below that it is a SIGKILL rather than an error.\n //\n // The exemption was also solving almost nothing. The band of symbol-table sizes where this\n // check refuses a read that a full load would have completed is bounded above by the memory\n // guard's own 6x symbol term: it is empty for any heap of 2GB or less, and 7MB wide at 4GB.\n validateSymbolTableSizeEarly(symbolBytes, this._path, retainedBytes);\n\n // Validate the header numbers before they are used to size anything. Without this, a NaN or\n // negative value reaches a read's length and surfaces as a raw Node RangeError.\n //\n // Through the functions a whole-file read validates them with later, so a window does not change\n // what a caller is told about the header. This used to report `Invalid header value: NoOfRecords`\n // where `fromQvd` without a window, `iterate` and `readMetadata` report `Invalid number of records`.\n // `Offset` needs no check here: `validateHeaderStructure` has refused an unusable one already.\n validateRecordSize(recordSize, this._path, 'readData');\n validateRecordCount(totalRows, this._path, 'readData');\n\n // What the file has to contain for the window to exist in it: the header, the symbol table, and\n // every record up to the window's last, since the window's records sit behind the ones it skips.\n // A window deep in a large file still reads only what it covers - the taxi fixture's last hundred\n // rows are a 0.4MB read rather than a 38MB one - but the file has to reach that far.\n const fileBytesRequired = indexTableOffset + (resolved.offset + rowsToLoad) * recordSize;\n\n // The header's numbers may not describe the file on disk: a truncated download, an interrupted\n // copy, a file still being written, or a header crafted to mislead. Refused here, before anything\n // past the header is read, with the message a window has always given for it.\n if (fileBytesRequired > fileSize) {\n throw new QvdCorruptedError('The file is shorter than its header claims.', {\n file: this._path,\n fileSize,\n requiredBytes: fileBytesRequired,\n stage: 'readData',\n });\n }\n\n this._emitProgress('read', 1, 1);\n }\n\n /**\n * Reads one byte range of the open file into a buffer.\n *\n * Read in bounded chunks, checking bytesRead each time. A single fs.read call with a length of\n * 2^31 or more does not throw - it trips a C++ assertion and aborts the whole process, which no\n * try/catch can intercept.\n *\n * @param {Buffer} target The buffer to read into.\n * @param {number} targetOffset Where in it to write.\n * @param {number} byteCount How many bytes to read.\n * @param {number} filePosition Where in the file to read from.\n * @param {number} requiredBytes How far into the file the read has to reach, for the error.\n * @throws {QvdCorruptedError} If the file ends before the range does.\n * @private\n */\n async _readAt(target, targetOffset, byteCount, filePosition, requiredBytes) {\n assert(this._handle && this._failed, 'The QVD file is not open.');\n\n const handle = this._handle;\n const failed = this._failed;\n let done = 0;\n\n while (done < byteCount) {\n const length = Math.min(READ_CHUNK_SIZE, byteCount - done);\n // @ts-ignore - Buffer type compatibility\n const {bytesRead} = await handle.read(target, targetOffset + done, length, filePosition + done).catch(failed);\n\n if (bytesRead === 0) {\n throw new QvdCorruptedError('Unexpected end of file while reading QVD data.', {\n file: this._path,\n fileSize: this._fileSize,\n // Two numbers, because they stopped being the same one when a window began reading two\n // ranges: `bytesRead` is how much of this range arrived, `filePosition` is where in the\n // file it gave up. Reporting the position under the name of the count made a windowed\n // read of a truncated file claim tens of megabytes had been read when a few hundred\n // bytes had.\n bytesRead: done,\n filePosition: filePosition + done,\n requiredBytes,\n stage: 'readData',\n });\n }\n\n done += bytesRead;\n }\n }\n\n /**\n * Bytes of the file a read holds outside the heap while it works, beside the codes the guard counts for\n * itself: the symbol areas it reads, and the one buffer its records come through.\n *\n * The areas are counted whole, although the read lets each range go once its fields are parsed, because\n * two ranges are both live when a field of one is parsed between two fields of the other - the order the\n * caller asked for the fields decides it, so the sum is what holds in every order. The slice is the\n * buffer `_forEachSlice` will allocate, sized by `_sliceRowsFor` so that the charge and the allocation\n * are one expression rather than two that agree today.\n *\n * @param {number} symbolBytes Bytes of symbols the read will read.\n * @param {number} rows Records it will read.\n * @param {number} recordSize Bytes per record.\n * @return {number} Bytes.\n * @private\n */\n _bytesHeldBy(symbolBytes, rows, recordSize) {\n const usable = Number.isSafeInteger(rows) && Number.isSafeInteger(recordSize) && rows > 0 && recordSize > 0;\n\n return symbolBytes + (usable ? this._sliceRowsFor(rows, recordSize) * recordSize : 0);\n }\n\n /**\n * Records the one buffer holds while a read of `rowCount` records goes through it.\n *\n * A slice is `sliceBytes` of records, rounded down to a whole record, or every record the read has left\n * when that is fewer - and at least one, since a read of a record wider than `sliceBytes` still has to\n * hold that record. The single definition: `_forEachSlice` allocates from it and the memory guard is\n * charged from it, so a change to how a read slices cannot leave the guard pricing the old rule.\n *\n * @param {number} rowCount Records the read will read.\n * @param {number} recordSize Bytes per record.\n * @return {number} Records in one slice.\n * @private\n */\n _sliceRowsFor(rowCount, recordSize) {\n return Math.max(1, Math.min(rowCount, Math.floor(this._sliceBytes / Math.max(1, recordSize))));\n }\n\n /**\n * What a read holds in bytes of the file, for the memory guard: what it holds now, and what a read\n * following either piece of advice a refusal can carry would hold instead.\n *\n * The two knobs are not the same knob, which is why there are two functions rather than one. A smaller\n * `limit` is a smaller window, so every record the read touches is one of fewer - the symbol-usage pass\n * included, since it reads the window. A smaller `chunkSize` leaves the window exactly where it is and\n * only changes how much of it is decoded at a time, so a read with that pass still ahead of it holds the\n * window's slice however small the chunk. Priced with `forRows`, such a chunk was charged for the records\n * of one chunk and then held sixteen megabytes more than that.\n *\n * @param {number} symbolBytes Bytes of symbols the read will read.\n * @param {number} windowRows Rows the read covers.\n * @param {number} recordSize Bytes per record.\n * @param {{rows: number, perChunk: number}|null} liveRows Rows held at one instant - see `_prepare`.\n * @param {boolean} analysisAhead Whether the symbol-usage pass has still to run.\n * @return {{held: number, forRows: (rows: number) => number, forChunk: (rows: number) => number}} What\n * this read holds, what a read of so many rows would hold, and what one reading so many rows a chunk\n * would hold.\n * @private\n */\n _bytesHeld(symbolBytes, windowRows, recordSize, liveRows, analysisAhead, freshSymbolBytes = null) {\n return {\n held: this._bytesHeldBy(symbolBytes, this._recordsAtOnce(windowRows, liveRows, analysisAhead), recordSize),\n // What it would hold having closed the file and opened it again: every selected column read fresh,\n // because nothing is cached any more. Higher than `held`, not lower - a cached column this read\n // selects costs nothing to read now and would cost its area then. Without it the counterfactual\n // that decides whether releasing helps was answered against the warm figure and said yes too often.\n afterRelease:\n freshSymbolBytes === null\n ? null\n : this._bytesHeldBy(freshSymbolBytes, this._recordsAtOnce(windowRows, liveRows, analysisAhead), recordSize),\n // A window of so many rows reads so many records at a time, and the pass that reads it ahead of the\n // decode reads the same rows, so the buffer is sized from the rows either way.\n forRows: (rows) => this._bytesHeldBy(symbolBytes, rows, recordSize),\n // A chunk of so many rows, over this read's window - which is what `chunkSize` changes and what it\n // leaves alone. `_recordsAtOnce` is what answers that, given a chunk size as the rows held at once.\n forChunk: (rows) =>\n this._bytesHeldBy(symbolBytes, this._recordsAtOnce(windowRows, {rows, perChunk: 1}, analysisAhead), recordSize),\n };\n }\n\n /**\n * Whether a read takes the symbol-usage pass, which reads the window's records before the symbol table\n * is parsed and so before the first chunk is built.\n *\n * The one statement of the condition. `_prepare` asks it to decide, and `_readData` asks it before the\n * header has been parsed, to know what to charge the memory guard: a read with the pass ahead of it\n * holds a whole slice of records, and a read without it holds only what it reads at a time. Said in two\n * places, the two would drift and a read would be charged for one path and take the other - which fails\n * open for a chunked read, and that is the direction the guard exists to prevent.\n *\n * Any window that does not cover the whole file is a candidate, which includes one bounded by its offset\n * rather than by its limit. Covering every row rules it out, however the window was spelled -\n * `{offset: 0, limit: n}` over all n rows, or an `iterate` of them. Such a read needs every symbol any\n * row uses, which is what `estimateMemoryUsage` assumes for a full read as well, so the pass has nothing\n * to filter. It is not free: since the records are read as they are decoded rather than held in one\n * buffer, the pass reads the window's records and the decode then reads them again. A window that really\n * is a window pays that for the symbols it saves parsing; a window that is a full read in disguise paid\n * it for nothing.\n *\n * The threshold is an option rather than a constant so this path can be exercised with a small fixture:\n * it is the most intricate code in the reader, and the only files large enough to reach the 50MB default\n * are ones no repository should be carrying around. It measures the whole table rather than the areas a\n * read selects, because what the pass saves is parsing work across the table.\n *\n * @param {QvdRowWindow} window The window as the caller spelled it.\n * @param {{offset: number, limit: number}} resolved Where it lands in this file.\n * @param {number} totalRows Rows the file declares.\n * @param {number} symbolTableLength The symbol table's declared length.\n * @return {boolean} Whether the pass will run.\n * @private\n */\n _analysisWouldRun(window, resolved, totalRows, symbolTableLength) {\n return (\n resolved.limit < totalRows &&\n (window.limit !== null || window.offset > 0) &&\n symbolTableLength > this._symbolFilteringThreshold\n );\n }\n\n /**\n * Records a read holds at one time, which is what its record buffer is sized from.\n *\n * A slice holds `sliceBytes` of records, or every record the read has left to read when that is fewer -\n * so what it costs depends on how many a read asks for at a time, not on how many it covers. An\n * iteration asks for a chunk: `iterate({limit: 20_000_000, chunkSize: 1000})` reads a thousand records at\n * a time however many its window covers, and charging it a full slice would refuse it for 16 MiB it never\n * allocates. The symbol-usage pass is the exception, because it reads the whole window in slices of its\n * own before the first chunk is built, so a read that still has that pass ahead of it is charged for it.\n *\n * @param {number} windowRows Rows the read covers.\n * @param {{rows: number, perChunk: number}|null} liveRows Rows held at one instant - see `_prepare`.\n * @param {boolean} analysisAhead Whether the symbol-usage pass has still to run.\n * @return {number} Records read at one time.\n * @private\n */\n _recordsAtOnce(windowRows, liveRows, analysisAhead) {\n const chunkRows =\n liveRows === null ? windowRows : Math.max(1, Math.floor(liveRows.rows / Math.max(1, liveRows.perChunk)));\n\n return analysisAhead ? Math.max(windowRows, chunkRows) : chunkRows;\n }\n\n /**\n * The fields this reader will be holding the symbols of once this read has finished.\n *\n * The ones it selects, and - while paging - the ones it decoded for an earlier page and kept. That\n * union is what the memory checks have to be sized by, because it is what is live: a reader four\n * pages into a wide file holds four columns' values whether or not this page asks about them, and a\n * check sized by this page alone would approve a fifth column that does not fit beside them.\n *\n * The same set for every check, so the ceilings, the guard and the pre-flight cannot disagree about\n * what a paging read costs. Without a cache it is just the selection, which is what every one-shot\n * read has always been sized by.\n *\n * @param {Array<any>} selected The fields this read selects.\n * @param {Array<any>} all Every field in the header, to find a cached one by name.\n * @return {Array<any>} The fields whose symbols will be live.\n * @private\n */\n _fieldsHeldAfter(selected, all) {\n if (this._symbolCache === null || this._symbolCache.size === 0) {\n return selected;\n }\n\n const names = new Set(selected.map((/** @type {any} */ field) => field['FieldName']));\n const cached = all.filter(\n (/** @type {any} */ field) =>\n !names.has(field['FieldName']) && this._symbolCache !== null && this._symbolCache.has(field['FieldName']),\n );\n\n return [...selected, ...cached];\n }\n\n /**\n * The fields whose symbol areas this read will actually read.\n *\n * The selection, less anything already decoded and kept. `_fieldsHeldAfter` answers what the read will\n * be *holding*, which is the right figure for the heap; this is the right one for the bytes it buffers\n * while parsing and for the I/O it reports, because a cached column's area is left out of the plan\n * entirely and never read.\n *\n * Sized by the wrong one of the two, a warm page was charged external bytes for buffers it never\n * allocates - and external bytes bind against a container limit, so a page that fits could be refused -\n * and `estimate.readBytes` claimed I/O it does not perform: on four columns with three cached it\n * reported 3,155,600 bytes for a read of 788,930.\n *\n * @param {Array<any>} selected The fields this read selects.\n * @return {Array<any>} The fields whose areas will be read.\n * @private\n */\n _fieldsReadBy(selected) {\n if (this._symbolCache === null || this._symbolCache.size === 0) {\n return selected;\n }\n\n return selected.filter(\n (/** @type {any} */ field) => this._symbolCache !== null && !this._symbolCache.has(field['FieldName']),\n );\n }\n\n /**\n * Keeps what this reader decodes, so that a later read of the same file does not decode it again.\n *\n * For a caller reading one file many times over - a `QvdFile` and its pages - and off by default,\n * because every other entry point is one read and would only be holding values nobody will ask for\n * again. Decoding the symbols is 72% of a page of a hundred rows from a 300,000-row file; the rest is\n * the open, the header, the records and the rows.\n *\n * It turns the two-pass symbol path off with it. That path decodes only the symbols a window's rows\n * use, which is right for one read and wrong for a cache: a later page asking for a row that uses a\n * skipped symbol would read `undefined` where the value is. So a cached field is always a whole\n * field, walked and checked against its `NoOfSymbols` like any other.\n *\n * @return {void}\n */\n beginPaging() {\n this._symbolCache = new Map();\n }\n\n /**\n * Reads with the fields the caller names for this read alone, rather than the reader's own.\n *\n * A `QvdFile` is opened once and its pages may each name a projection, so the selection cannot be\n * fixed at construction as it is for every other entry point.\n *\n * It holds until the next call replaces it rather than being cleared by the read, so **every caller\n * sets it before every read**, passing the file's own fields where the page named none. A caller that\n * relied on it being empty would instead get the projection of whatever ran last: that is what made a\n * `check()` naming no fields answer for the previous page's columns.\n *\n * @param {Array<string>|null|undefined} fields The fields, or undefined to use the reader's own.\n * @return {void}\n */\n selectForNextRead(fields) {\n if (fields !== undefined) {\n this._requestedFields = fields;\n }\n }\n\n /**\n * Watches the next read with the caller's `onProgress` and `signal`, rather than the reader's own.\n *\n * Both belong to one call, and a reader is told them when it is built - so a `QvdFile` page that named\n * either used to get a reader of its own. That made passing a progress callback change what the read\n * did rather than only observing it: a fresh reader is not paging, so it took the two-pass symbol\n * path, reported a different `loadStats.symbolFiltering`, and cached nothing. An observer must not\n * change what it observes, and a caller must not have to choose between cancelling a page and paging\n * cheaply.\n *\n * Like `selectForNextRead`, it holds until the next call replaces it rather than being cleared by the\n * read, so a caller that sets it for one page and not the next is still watched on the next - pass the\n * file's own watchers explicitly, as `QvdFile._page` does, rather than leaving them out.\n *\n * @param {{onProgress?: Function, signal?: AbortSignal}} [watchers] What this read is watched with.\n * @return {void}\n */\n observeNextRead({onProgress, signal} = {}) {\n // The same rules the constructor applies, because this is the same pair arriving by another door.\n // Assigning them unchecked put an `onProgress` of the wrong type past every check and into\n // `_emitProgress`, where it failed as a raw `TypeError` rather than a `QvdValidationError` naming\n // the option - and a signal-shaped object that is not one cancelled nothing, silently.\n validateWatchers(onProgress, signal, this._path);\n\n this._onProgress = onProgress;\n this._signal = signal;\n }\n\n /**\n * Whether the symbol-usage pass runs for this read, cache and all.\n *\n * `_analysisWouldRun` answers whether the window wants the pass; a paging read never takes it, because\n * a column decoded in part cannot be kept. Asked in one place because it was asked in two and they\n * disagreed: the pass was gated on the cache while the memory charge and `estimate.readBytes` were\n * not, so every page of a file above the threshold was charged a slice of records it never buffered\n * and reported twice the bytes it read.\n *\n * @param {QvdRowWindow} window The window as the caller spelled it.\n * @param {{offset: number, limit: number}} resolved Where it lands in this file.\n * @param {number} totalRows Rows the file declares.\n * @param {number} symbolTableLength The symbol table's declared length.\n * @return {boolean} Whether the pass will run.\n * @private\n */\n _analysisAhead(window, resolved, totalRows, symbolTableLength) {\n return this._symbolCache === null && this._analysisWouldRun(window, resolved, totalRows, symbolTableLength);\n }\n\n /**\n * Empties the cache when the header in front of us is not the one it was decoded from.\n *\n * The fingerprint is what a rewrite moves: the file's identity on disk - device, inode, modification\n * time and size - and then the header numbers, down to each cached field's own offset, length and\n * symbol count.\n *\n * The header numbers alone were not enough, and the gap is not exotic. `QvdFileWriter` carries\n * `CreateUtcTime` over from the metadata it is handed, so reading a QVD, changing one text to another\n * of the same byte length and writing it back leaves `CreateUtcTime`, `NoOfRecords`, `Offset` and\n * every field's `Offset`, `Length` and `NoOfSymbols` exactly as they were - a different file the\n * fingerprint could not tell from the first. The filesystem sees it either way: an atomic write\n * renames a new file into place, which changes the inode, and an in-place one moves `mtimeMs`.\n *\n * @return {void}\n * @private\n */\n _forgetCacheIfFileChanged() {\n if (this._symbolCache === null || this._symbolCache.size === 0) {\n return;\n }\n\n if (this._cachedFor !== this._fileFingerprint()) {\n this._symbolCache = new Map();\n this._cachedFor = null;\n }\n }\n\n /**\n * What identifies the file this reader's cache was decoded from.\n *\n * @return {string} The fingerprint.\n * @private\n */\n _fileFingerprint() {\n assert(this._header && this._allFields, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n\n return [\n // First, because it is the only part that moves when a rewrite preserves the header's numbers.\n this._fileIdentity,\n header['CreateUtcTime'],\n header['NoOfRecords'],\n header['Offset'],\n ...this._allFields.map(\n (/** @type {any} */ field) =>\n `${field['FieldName']}:${field['Offset']}:${field['Length']}:${field['NoOfSymbols']}`,\n ),\n ].join('|');\n }\n\n /**\n * Drops everything this reader has decoded, so that nothing outlives the caller that wanted it.\n *\n * @return {void}\n */\n endPaging() {\n this._symbolCache = null;\n this._cachedFor = null;\n }\n\n /**\n * The symbol table's length, as much of it as the file holds: what the header declares, cut short where\n * the file ends. Known before a byte of the table is read, so everything that can refuse the table is\n * checked on this, before the table is allocated.\n *\n * A file that ends inside its symbol table is measured to where it ends, and the fields whose areas it cut\n * short are refused as `Symbol data extends beyond buffer` when their metadata is checked - what a\n * whole-file read has always said of such a file. A window has refused it already, before reading anything.\n *\n * @return {number} Bytes.\n * @private\n */\n _symbolTableLength() {\n assert(\n this._symbolTableOffset !== null && this._indexTableOffset !== null && this._fileSize !== null,\n 'The QVD file header has not been parsed before its symbol table was measured.',\n );\n\n const declared = this._indexTableOffset - this._symbolTableOffset;\n\n return Math.max(0, Math.min(declared, this._fileSize - this._symbolTableOffset));\n }\n\n /**\n * Where each selected field's symbols are, as ranges of the symbol table this read will read.\n *\n * A field's `Offset` and `Length` say exactly where its symbols are, so a read of some of a file's fields\n * has no reason to read the areas of the rest (#122). Qlik writes the areas one after another in field\n * order, so ranges that touch are merged: a read of every field is one range, and so is a read of fields\n * that happen to be neighbours. A read of one field of twenty reads that field's area alone.\n *\n * A field whose symbols this reader already holds is left out, because its bytes are not wanted: the\n * ranges are what gets read, and including a cached field's span had a page read every byte of every\n * column it named, cached or not. Measured on four columns of 20,000 distinct texts, a page naming all\n * four with three of them cached read all four columns' bytes - 1,155,600 of them, where 288,930 were\n * needed. The decode was saved and the I/O was not, which on the files #122 is about is the whole cost.\n *\n * Built once per read, from the fields the read must read, and each field's metadata is checked as it is\n * added - a range is arithmetic on `Offset` and `Length`, and those have to be inside the table first.\n * `_parseSymbolTable` checks every field of the file, selected or not, before it parses any.\n *\n * @return {{ranges: Array<{start: number, end: number, fields: number, buffer: Buffer|null}>,\n * byField: Map<any, {range: {start: number, end: number, fields: number, buffer: Buffer|null},\n * start: number, end: number}>}} The ranges, and where in its range each field's area sits.\n * @private\n */\n _symbolAreaPlan() {\n if (this._symbolAreas !== null) {\n return this._symbolAreas;\n }\n\n assert(this._selectedFields, 'The QVD file fields have not been resolved before their symbols were read.');\n\n const tableLength = this._symbolTableLength();\n const toRead = this._selectedFields.filter(\n (/** @type {any} */ field) => this._symbolCache === null || !this._symbolCache.has(field['FieldName']),\n );\n const areas = toRead.map((/** @type {any} */ field) => {\n validateFieldMetadata(field, tableLength, this._path);\n\n const start = headerInteger(field['Offset']);\n\n return {field, start, end: start + headerInteger(field['Length'])};\n });\n\n /** @type {Array<{start: number, end: number, fields: number, buffer: Buffer|null}>} */\n const ranges = [];\n /** @type {Map<any, {range: any, start: number, end: number}>} */\n const byField = new Map();\n\n for (const area of [...areas].sort((a, b) => a.start - b.start)) {\n const last = ranges.at(-1);\n // Merged when this area begins where the last one ended, or inside it. Overlapping areas are refused\n // by `validateSymbolAreas` before anything is parsed; merging them here only decides what is read.\n const range =\n last !== undefined && area.start <= last.end\n ? last\n : {start: area.start, end: area.end, fields: 0, buffer: null};\n\n if (range !== last) {\n ranges.push(range);\n }\n\n range.end = Math.max(range.end, area.end);\n range.fields += 1;\n byField.set(area.field, {range, start: area.start, end: area.end});\n }\n\n this._symbolAreas = {ranges, byField};\n\n return this._symbolAreas;\n }\n\n /**\n * One field's symbols, as bytes: the range that holds them, read from the open file the first time a field\n * of that range needs it.\n *\n * @param {any} field The field, one this read selected.\n * @return {Promise<{buffer: Buffer, start: number, end: number, base: number}>} Its area, as a range of\n * `buffer`, with where that buffer starts in the symbol table - what an error adds back to say where a\n * damaged symbol is in the file, rather than where it is in the bytes this read happened to read.\n * @throws {QvdValidationError} If the range is larger than half the heap.\n * @private\n */\n async _symbolAreaOf(field) {\n assert(\n this._header && this._symbolTableOffset !== null,\n 'The QVD file header has not been parsed before its symbols were read.',\n );\n\n const area = this._symbolAreaPlan().byField.get(field);\n\n assert(area, 'A field this read did not select has no symbol area.');\n\n const {range} = area;\n\n if (range.buffer === null) {\n const length = range.end - range.start;\n\n // The ceiling `_parseSymbolTable` applies, here as well because the two-pass count reads a field's\n // symbols before that runs. Before the allocation, where it used to come after the table had been\n // read: a whole-file read makes no early check, and the memory guard stands aside when the header\n // does not describe the file, so a damaged header in a large file was allocated whatever it claimed,\n // up to the size of the file.\n validateSymbolTableSize(length, this._path, headerInteger(this._header['QvdTableHeader']['NoOfRecords']));\n\n // Zero-filled rather than allocUnsafe: if any path ever failed to overwrite part of it, the result\n // would be zeros rather than leaked process memory.\n const buffer = Buffer.alloc(length);\n const from = this._symbolTableOffset + range.start;\n\n await this._readAt(buffer, 0, length, from, from + length);\n\n range.buffer = buffer;\n }\n\n return {buffer: range.buffer, start: area.start - range.start, end: area.end - range.start, base: range.start};\n }\n\n /**\n * Lets go of a field's symbols once they are parsed, and of the bytes of its range once every field in it\n * has been.\n *\n * Every text is copied out of the bytes as it is decoded, so what the read keeps is the values. A read of\n * one field of a file whose other fields are large therefore holds that field's bytes and no others.\n *\n * @param {any} field The field whose symbols are parsed.\n * @private\n */\n _releaseSymbolArea(field) {\n const area = this._symbolAreaPlan().byField.get(field);\n\n assert(area, 'A field this read did not select has no symbol area.');\n\n area.range.fields -= 1;\n\n if (area.range.fields === 0) {\n area.range.buffer = null;\n }\n }\n\n /**\n * Reads records from the open file a slice at a time, and hands each slice to `visit`.\n *\n * One buffer of at most `sliceBytes` holds a slice, and is reused for the next one, so a read of any\n * number of records holds that much of them and no more. Cancellation is checked before each slice.\n *\n * @param {number} firstRow The file row of the first record.\n * @param {number} rowCount How many records.\n * @param {number} recordSize Bytes per record.\n * @param {(slice: Buffer, done: number, count: number) => void|Promise<void>} visit Called with each\n * slice's records, how many records came before it, and how many it holds.\n * @private\n */\n async _forEachSlice(firstRow, rowCount, recordSize, visit) {\n if (rowCount === 0) {\n return;\n }\n\n assert(this._indexTableOffset !== null, 'The QVD file header has not been parsed before its records were read.');\n\n const sliceRows = this._sliceRowsFor(rowCount, recordSize);\n const slice = Buffer.alloc(sliceRows * recordSize);\n const requiredBytes = this._indexTableOffset + (firstRow + rowCount) * recordSize;\n\n for (let done = 0; done < rowCount; done += sliceRows) {\n this._throwIfAborted();\n\n const count = Math.min(sliceRows, rowCount - done);\n const records = slice.subarray(0, count * recordSize);\n\n await this._readAt(\n records,\n 0,\n records.length,\n this._indexTableOffset + (firstRow + done) * recordSize,\n requiredBytes,\n );\n await visit(records, done, count);\n }\n }\n\n /**\n * Parses the XML header of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n */\n async _parseHeader() {\n if (!this._headerBuffer) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const HEADER_DELIMITER = '\\r\\n\\0';\n\n const headerBeginIndex = 0;\n const headerDelimiterIndex = this._headerBuffer.indexOf(HEADER_DELIMITER, headerBeginIndex);\n\n // Check explicitly for -1 (not found) rather than using falsy check (!headerDelimiterIndex)\n // because indexOf() returns 0 when the delimiter is at position 0, which is a valid buffer index.\n // Using !0 would incorrectly treat position 0 as an error.\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n const headerBuffer = this._headerBuffer.subarray(headerBeginIndex, headerEndIndex);\n\n /*\n * The following instruction parses the XML header into a JSON object. It is important to\n * note that the object is a plain JavaScript object and not an instance of representative\n * class. Hence, types are not casted, therefore all raw values are strings, and child nodes\n * that contain an array of objects are not represented directly as an array but as an object\n * with a property, named like the array item tag, that is an array of the actual objects. The\n * same applies to child nodes that contain a single object and the root node.\n *\n * The following XML representation of the QVD header for example...\n *\n * <QvdTableHeader>\n * ...\n * <Fields>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * </Fields>\n * </QvdTableHeader>\n *\n * ...is parsed into the following object:\n *\n * {\n * QvdTableHeader: {\n * ...,\n * Fields: {\n * QvdFieldHeader: [\n * { FieldName: 'Field1', ...},\n * { FieldName: 'Field2', ...}\n * ]\n * }\n * }\n * }\n */\n\n // A header nobody has checked yet. Cleared before the parse, so that whatever happens next nothing\n // trusts the verdict on the last one. A reader is not single-use: a second read parses the file's\n // header again, and the file may have been replaced in between. When the flag survived that, a\n // second read of other fields only decoded a new, unchecked header - a Bias out of range included.\n this._fieldBitMetadataValidated = false;\n\n this._header = await parseHeaderXml(headerBuffer.toString(), this._path, 'parseHeader');\n\n // The field list, checked - a list of field elements, each with a name no other has - so every\n // path downstream can assume one. Checked once, at the point the header becomes available.\n const fieldList = validateHeaderStructure(this._header, this._path, 'parseHeader');\n\n /*\n * Because the three parts of the QVD file, header, symbol and index table, are seamlessly concatenated,\n * the end of the respective previous part is the beginning of the next part.\n */\n this._headerOffset = headerBeginIndex;\n this._symbolTableOffset = headerEndIndex;\n this._indexTableOffset = this._symbolTableOffset + headerInteger(this._header['QvdTableHeader']['Offset']);\n\n // The file's fields, and the caller's selection of them, resolved once and here.\n //\n // Everything downstream is positionally aligned by the order `selectFields` returns - the\n // symbol table, the decoded columns and `columns` are three arrays indexed by the same\n // position - so they have to come from one derivation rather than from three that happen to\n // agree. That is the same rule `fieldGeometry` exists to enforce for the bit layout, and the\n // consequence of breaking it is the same: a misalignment decodes cleanly and returns another\n // column's values with nothing thrown.\n // `fieldList` as `validateHeaderStructure` returned it, rather than normalised again here: it is\n // already an array of named field elements, so recomputing it would be a second derivation that\n // happens to agree - which is the thing this caching exists to stop, one scope up.\n this._allFields = fieldList;\n this._selectedFields = selectFields(this._allFields, this._requestedFields, this._path);\n }\n\n /**\n * Establishes the geometry of the index table, and validates it.\n *\n * Both passes over the index table - the symbol-usage analysis and the decode itself - need\n * exactly this, and they used to derive it separately with two copies of the same bit\n * unpacking. The copies are the reason the bias comment in the analysis pass warns so loudly\n * about keeping the sign in step with the other one: the two could drift, and #113 is what\n * that looks like when they do. There is one copy now.\n *\n * @param {QvdRowWindow} window The rows of interest, as file row indices.\n * @param {string} stage Stage name for any error raised here.\n * @return {{fields: Array<any>, recordSize: number, totalRows: number, rowsToLoad: number,\n * firstRow: number}} The record geometry: the window's `rowsToLoad` records start at file row\n * `firstRow`, and `_forEachSlice` reads them.\n * @private\n */\n _planIndexTable(window, stage) {\n if (!this._handle || !this._header || !this._indexTableOffset || !this._selectedFields || !this._allFields) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage,\n },\n );\n }\n\n const allFields = this._allFields;\n const fields = this._selectedFields;\n\n // Size of a single row of the index table in bytes\n const recordSize = headerInteger(this._header['QvdTableHeader']['RecordByteSize']);\n const totalRows = headerInteger(this._header['QvdTableHeader']['NoOfRecords']);\n const indexTableLength = headerInteger(this._header['QvdTableHeader']['Length']);\n\n // Resolved again rather than trusted. Callers already pass a window resolved against this\n // file, and resolving a resolved window returns it unchanged - but this is the function that\n // decides which bytes get decoded, and it should not be possible to reach it with a window\n // that runs off the end of the file.\n const {offset: firstRow, limit: rowsToLoad} = resolveWindow(window, totalRows);\n\n assert(this._fileSize !== null, 'The QVD file has not been measured before its records were planned.');\n\n // Validate all index table metadata, against the file: the records are read from it as they are\n // decoded, so it is the file that has to hold them. A whole-file read used to check against a\n // buffer holding the whole file, which is the same thing, so its messages are unchanged.\n validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n this._indexTableOffset,\n this._fileSize,\n rowsToLoad,\n this._path,\n this._fileSize,\n firstRow,\n 0,\n );\n\n // Validate BitOffset and BitWidth for every field in the file, selected or not, once.\n //\n // A projection must not make a corrupt file readable: if a field's bit metadata is nonsense,\n // `{fields: [...]}` that happens to leave it out should not quietly succeed where a full read\n // refuses. The check costs nothing - it reads header numbers - and keeping it whole means one\n // answer to \"does this file decode\".\n //\n // Once per header, not once per window: the metadata is the header's and does not change\n // between chunks, so a 200-chunk iteration over 20 fields was re-parsing the same 4,000\n // strings. `_parseHeader` clears the flag, so a reader reused on a file that has changed\n // checks the new header. It stays *here*, after validateIndexTableMetadata, rather than\n // moving up into `_prepare` - that call is what establishes `recordSize` is usable, and\n // validating bit offsets against an unusable record size reports the wrong fault for the\n // same file.\n if (!this._fieldBitMetadataValidated) {\n for (const field of allFields) {\n validateFieldBitMetadata(field, recordSize, this._path);\n }\n\n // After every field has passed on its own, so a field that runs past the record is reported as\n // that rather than as overlapping whatever it ran into.\n validateBitFields(allFields, this._path);\n\n this._fieldBitMetadataValidated = true;\n }\n\n // The decoder indexes into each slice without per-row bounds checks, which is only sound because\n // every slice holds whole records: `_forEachSlice` reads them whole, and refuses a file that ends\n // before they do. validateIndexTableMetadata has already established that the file holds the\n // window's `rowsToLoad` records - the declared table reaches the end of the window, and the file\n // holds the declared table.\n //\n // Stated as an assertion rather than dropped, because relaxing any of those checks later would\n // make a read fall short of the window, and a record that is not there would decode as whatever\n // the slice held before. Better to fail here.\n const windowEnd = this._indexTableOffset + (firstRow + rowsToLoad) * recordSize;\n assert(\n rowsToLoad === 0 || recordSize === 0 || windowEnd <= this._fileSize,\n `The window's records end at byte ${windowEnd} of a file of ${this._fileSize}, ` +\n `but ${rowsToLoad} were validated as present.`,\n );\n\n return {fields, recordSize, totalRows, rowsToLoad, firstRow};\n }\n\n /**\n * Analyzes the index table to determine which symbols are actually needed.\n * This is used for two-pass symbol filtering optimization.\n *\n * Only the selected fields are analysed. An unselected field's symbols are never parsed, so\n * there is nothing for a usage set to filter and decoding its column would be a pass over the\n * whole window for an answer nobody reads.\n *\n * @param {QvdRowWindow} window The rows to analyse.\n * @return {Promise<Array<Set<number>>>} One set of needed symbol indices per selected field, in\n * the same order `_parseSymbolTable` walks them.\n * @private\n */\n async _analyzeIndexTableSymbolUsage(window) {\n const {fields, recordSize, rowsToLoad, firstRow} = this._planIndexTable(window, 'analyzeIndexTableSymbolUsage');\n\n // One set per field, indexed by position rather than keyed by field name.\n //\n // By position because every other per-field array in this reader is - the symbol table, the\n // decoded columns and `columns` are all indexed the same way - and a name-keyed map is not\n // the same thing when a header declares two fields with one name. Qlik does not produce such\n // a file, and `validateHeaderStructure` now refuses one, but while nothing did, keying by name\n // made the second field's set overwrite the first's: the first field was then filtered against\n // the wrong set, every symbol it needed and the other did not read back as `undefined`, and\n // nothing threw. Measured on a copy of `lego/colors.qvd` with a field renamed to collide: a\n // plain read gave `'Black'` where a filtered read gave `undefined`. It only bit above\n // `symbolFilteringThreshold`, which is to say only on the large files where it is hardest to\n // notice - the #113 failure shape exactly.\n /** @type {Array<Set<number>>} */\n const symbolUsage = [];\n\n // One slice of one column at a time, reused across every slice and every field.\n //\n // Bounded rather than sized to the window, because the answer this pass produces is a *set*\n // of distinct indices: the union over slices is the same set the whole window would give, so\n // there is no reason to hold the window. Sizing it to the window made the pass allocate four\n // bytes per row of a read whose entire purpose might be to hold only a chunk at a time -\n // `iterate({limit: 20_000_000, chunkSize: 1000})` allocated 80MB here while the memory guard\n // had been told the read holds 2,000 rows. A cgroup counts that 80MB and answers with a\n // SIGKILL, which is the uncatchable direction.\n //\n // Capping it is the fix rather than telling the guard about it: an allocation the guard has\n // to be told about is one more figure that can drift from what the code does, and this one\n // did not need to exist.\n const sliceRows = Math.min(rowsToLoad, ANALYSIS_SLICE_ROWS);\n const column = new Int32Array(sliceRows);\n\n // What the pass knows of each field so far. The records are read a slice at a time and every field\n // is decoded from each slice before the next is read, so this lives across slices.\n const state = fields.map((/** @type {any} */ field) => {\n const needed = new Set();\n symbolUsage.push(needed);\n\n // The bias is applied inside the decoder, which is the same call the parse pass makes.\n // When these were two separate unpackings, a sign difference here would have recorded the\n // wrong symbols as needed and every affected cell would have read back as undefined -\n // silently, because such an index still addresses a symbol, just one this pass left out.\n //\n // Decoded unchecked: the symbols are not parsed yet, so there is no count to check against.\n // `_parseIndexTable` decodes the same rows with the check and refuses an index that\n // addresses nothing. Until then it only has to be kept out of `needed`, which is not\n // harmless to fill: a damaged index table can hold a different index in every row.\n //\n // No index at or past `indexLimit` can address a symbol, so none is kept. It starts as the\n // most symbols the field's bytes can hold - each takes at least two, a type byte and the\n // terminator of an empty string - which costs nothing to know. That is not the symbols the\n // field has, though, so once `needed` outgrows `COUNT_SYMBOLS_PAST` they are counted and it\n // becomes that. Either way no index it leaves out could have addressed a symbol. An unusable\n // `Length` bounds nothing here, and `_parseSymbolTable` refuses the field anyway.\n //\n // The header's `NoOfSymbols` is not the start, although the parse refuses a field that does not\n // hold that many. It would keep the same set on a valid file, whose indices are all below it, and\n // it would not spare the count: one too large bounds nothing, and only the walk shows it is wrong.\n const length = headerInteger(field['Length']);\n\n return {\n field,\n needed,\n bitOffset: headerInteger(field['BitOffset']),\n bitWidth: headerInteger(field['BitWidth']),\n bias: headerInteger(field['Bias']),\n indexLimit: Number.isSafeInteger(length) && length >= 0 ? Math.ceil(length / 2) : Infinity,\n counted: false,\n };\n });\n\n await this._forEachSlice(firstRow, rowsToLoad, recordSize, async (records, done, recordCount) => {\n for (let first = 0; first < recordCount; first += sliceRows) {\n const count = Math.min(sliceRows, recordCount - first);\n\n for (const field of state) {\n // The decoder always counts records from the start of the buffer it is given, so a slice\n // is a matter of where that buffer starts - the same property that makes a row window\n // cheap in `_parseIndexTable`.\n decodeIndexColumn(\n first === 0 ? records : records.subarray(first * recordSize),\n recordSize,\n count,\n field.bitOffset,\n field.bitWidth,\n field.bias,\n column,\n );\n\n for (let row = 0; row < count; row++) {\n // A negative index references no symbol - it is NULL, or damage the decode refuses - and\n // neither does one at or past `indexLimit`, so neither is kept.\n if (column[row] >= 0 && column[row] < field.indexLimit) {\n field.needed.add(column[row]);\n }\n }\n\n // Checked once a slice rather than once a row, which keeps the loop above to what it was:\n // the set can outgrow the threshold by one slice at most before it is held to the count.\n if (!field.counted && field.needed.size > COUNT_SYMBOLS_PAST) {\n field.counted = true;\n field.indexLimit = Math.min(field.indexLimit, await this._countFieldSymbols(field.field));\n\n for (const index of field.needed) {\n if (index >= field.indexLimit) {\n field.needed.delete(index);\n }\n }\n }\n }\n }\n\n // Rows analysed, over the rows the window covers: the records are read once for every field, so a\n // field at a time is no longer the unit of progress.\n this._emitProgress('symbol-analysis', done + recordCount, rowsToLoad);\n });\n\n if (rowsToLoad === 0) {\n this._emitProgress('symbol-analysis', 0, 0);\n }\n\n return symbolUsage;\n }\n\n /**\n * How many symbols a field holds, for the symbol-usage pass, which runs before the symbols are parsed.\n *\n * The count is `countFieldSymbols`, the parse itself told to decode nothing, so it is the count\n * `_parseSymbolTable` will produce and `_parseIndexTable` will check against. The field's area is\n * validated before it is read, by `_symbolAreaPlan`, so a damaged `Offset`, `Length` or `NoOfSymbols` is\n * reported the same way wherever it is met. Its bytes are kept for the parse that follows. The walk checks the count against `NoOfSymbols` as the\n * parse does, so a field whose count is wrong is refused here, before the pass keeps anything on the\n * strength of it.\n *\n * @param {any} field The field's header.\n * @return {Promise<number>} Its symbols.\n * @throws {QvdCorruptedError} If the area is not inside the symbol table, a symbol runs past it, or it\n * holds a different number of symbols from its `NoOfSymbols`.\n * @private\n */\n async _countFieldSymbols(field) {\n const area = await this._symbolAreaOf(field);\n\n return countFieldSymbols(\n area.buffer,\n area.start,\n area.end,\n headerInteger(field['NoOfSymbols']),\n field['FieldName'],\n this._path,\n area.base,\n );\n }\n\n /**\n * Parses the symbol table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * A field the caller did not select is skipped whole. Its symbol area is neither scanned nor\n * parsed - the per-field `Offset` and `Length` say exactly where it is, so there is nothing to\n * walk past - and that is where field selection earns its keep. The index decode is cheap by\n * comparison; parsing symbols is not.\n *\n * @param {Array<Set<number>>|null} symbolsToKeep Optional set of symbol indices to keep per\n * selected field, indexed by position. If provided, only these symbols will be parsed\n * (two-pass filtering optimization).\n * @param {number} rowsToLoad Rows the read covers, for memory estimation.\n * @param {{rows: number, perChunk: number}|null} [liveRows=null] Rows held at one instant when\n * that is fewer than the window covers - see `_prepare`.\n */\n async _parseSymbolTable(symbolsToKeep = null, rowsToLoad = 0, liveRows = null) {\n if (\n !this._handle ||\n !this._header ||\n !this._symbolTableOffset ||\n !this._indexTableOffset ||\n !this._selectedFields ||\n !this._allFields\n ) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseSymbolTable',\n },\n );\n }\n\n const allFields = this._allFields;\n const fields = this._selectedFields;\n\n // The cache holds values decoded from one file, and a page re-opens the path rather than holding it,\n // so the file underneath can be replaced between pages - an upstream job rewriting it in place. Its\n // name would still match, and the old values would be used to resolve the new file's row codes:\n // plausible rows, silently wrong, which is the failure this library builds checks against (#124,\n // #247). Cheap to rule out, because the header is re-read for every page anyway.\n this._forgetCacheIfFileChanged();\n\n // Measured, not read: every check up to the parse needs only the length, so bytes one of them refuses\n // are never allocated. They are read once the checks have all passed.\n //\n // Two lengths, because two different things are being bounded. The ceiling bounds what this read will\n // hold - the areas of the fields it selects, which is the whole table only when it selects them all -\n // and `_symbolTableLength` bounds where those areas may sit, which is the table however few are read.\n //\n // The plan is built before the ceiling below rather than after it, and deliberately: the ceiling is\n // sized from the areas, and `_symbolAreaPlan` is what validates them - an area whose `Offset` or\n // `Length` is not a usable number, or that sits outside the table, is refused there. Sizing a check\n // from numbers nothing has checked is how a header talks its way past one. The visible consequence is\n // which error a file damaged in two ways at once reports: one whose fields are unusable *and* whose\n // table exceeds the ceiling is now refused for the fields, where before 2.0.6 it was refused for the\n // size. Both are true of it; the field error is the more specific, and it names the field.\n const symbolTableSize = this._symbolTableLength();\n const plan = this._symbolAreaPlan();\n\n // The areas this read will read, plus the columns an earlier page left decoded and live. The plan\n // covers only what is about to be read, which is the right number for the areas but the wrong one\n // for what the read will be holding when it finishes.\n const readSymbolBytes = plan.ranges.reduce((sum, range) => sum + (range.end - range.start), 0);\n const retainedBytes = symbolBytesOf(this._fieldsHeldAfter(fields, allFields).slice(fields.length), symbolTableSize);\n const symbolBytes = readSymbolBytes + retainedBytes;\n const totalRows = headerInteger(this._header['QvdTableHeader']['NoOfRecords']);\n const recordSize = headerInteger(this._header['QvdTableHeader']['RecordByteSize']);\n\n // SAFETY CHECK 1: Absolute ceiling to prevent pathological cases\n // Phase 2.5 optimization allows much larger symbol tables when using maxRows,\n // but we still need an absolute maximum to prevent truly extreme cases\n validateSymbolTableSize(symbolBytes, this._path, totalRows);\n\n // SAFETY CHECK 2: Dynamic memory validation, now against the symbol table's real size rather\n // than the size its header declared. _readData already ran this check before reading\n // anything; this is the more accurate second look, and the two agree on a well-formed file.\n //\n // Skipped on the same condition as the early one. This is the call that mattered: the\n // structural checks that identify a truncated file run in _parseIndexTable, after this, so\n // an estimate built on an inflated NoOfRecords would report a memory problem for a file\n // whose real problem is that it is short.\n if (this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolBytes,\n rowsToLoad,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n fields.length,\n this._materialisesRows,\n liveRows,\n this._bytesHeld(readSymbolBytes, rowsToLoad, recordSize, liveRows, false, symbolBytes - retainedBytes),\n // `symbolsToKeep` is non-null exactly when the symbol-usage pass has run, and a pass that has\n // run has read the window's records once already - so the read's total is two passes over them.\n readSymbolBytes + readPasses(symbolsToKeep !== null) * rowsToLoad * recordSize,\n this._symbolCache !== null,\n retainedBytes,\n );\n }\n\n // WARNING ZONE: Large files without maxRows parameter\n // Educate users about best practices but don't block\n warnLargeSymbolTable(\n symbolBytes,\n rowsToLoad,\n totalRows,\n fields.length,\n this._materialisesRows,\n this._symbolCache !== null,\n );\n\n /*\n * The symbol table is a contiguous byte array that contains all possible symbols/values of all fields/columns.\n * The symbols/values of one field are stored consecutively in the same order as the fields/columns are defined\n * in the header. The length of the symbol area as well as it's offset, relativ to the begin of the symbol\n * table, are also defined in the header.\n */\n\n // Validate every field's metadata, selected or not, to prevent buffer overflow attacks.\n //\n // Whole-file rather than whole-selection for the same reason the bit metadata is: a\n // projection must not turn a file a full read refuses into one it accepts. Reading header\n // numbers costs nothing next to parsing the symbols they describe.\n //\n // Then the areas against each other, once each is known to be inside the table: two fields whose\n // areas overlap would each parse some of the other's symbols as their own.\n for (const field of allFields) {\n validateFieldMetadata(field, symbolTableSize, this._path);\n }\n\n validateSymbolAreas(allFields, this._path);\n\n // Decode the symbols of each *selected* field, straight from the bytes into their two halves. Each\n // field's bytes are read when its turn comes, and let go of once they are decoded, so a read holds the\n // values it has parsed and the bytes of at most one range of the table. Phase 2.5 optimization: a symbol\n // the window does not use is walked past without decoding.\n //\n // Assigned when every field has parsed, rather than field by field, so a read refused part-way leaves\n // the reader describing no symbol table rather than half of one.\n /** @type {Array<import('./util/symbolParser.js').FieldSymbols>} */\n const symbolTable = [];\n\n for (const [position, field] of fields.entries()) {\n this._throwIfAborted();\n\n // A field this reader has already decoded, when it is paging. Measured on a 300,000-row file with\n // a 50,000-value text column, decoding the symbols is 72% of a page of a hundred rows - so a\n // viewer that pages through one file re-did, per page, nearly all the work of the page before it.\n //\n // Only whole fields are cached, and only a read that decoded all of a field's symbols may put one\n // in: `symbolsToKeep` means the walk skipped some, and a later page asking for a row that uses a\n // skipped symbol would read `undefined` from the cache rather than its value. `beginPaging` turns\n // the two-pass path off for that reason, so a cached field is always whole.\n const cached = this._symbolCache?.get(field['FieldName']);\n\n if (cached) {\n symbolTable.push(cached);\n this._emitProgress('symbol-table', position + 1, fields.length);\n continue;\n }\n\n const area = await this._symbolAreaOf(field);\n const parsed = parseFieldSymbols(\n area.buffer,\n area.start,\n area.end,\n // Checked against the symbols the area holds, which is the one check that sees a terminator\n // damaged in the middle of it (#124). A cached field was checked when it was decoded, which is\n // why the cache may only hold a field a full walk produced.\n headerInteger(field['NoOfSymbols']),\n // By position, matching how `_analyzeIndexTableSymbolUsage` built it. Both walk\n // `this._selectedFields`, so position is the one key that cannot collide.\n symbolsToKeep ? symbolsToKeep[position] : null,\n field['FieldName'],\n this._path,\n undefined,\n area.base,\n );\n\n symbolTable.push(parsed);\n\n if (this._symbolCache && symbolsToKeep === null) {\n if (this._symbolCache.size === 0) {\n this._cachedFor = this._fileFingerprint();\n }\n\n this._symbolCache.set(field['FieldName'], parsed);\n }\n\n this._releaseSymbolArea(field);\n this._emitProgress('symbol-table', position + 1, fields.length);\n }\n\n this._symbolTable = symbolTable;\n }\n\n /**\n * Parses the bit stuffed index table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * One `Int32Array` per field, filled by `decodeIndexColumn`, replacing an array per row filled\n * a bit at a time. The old route, per row, built an `Int32Array` of the record's bytes,\n * concatenated a binary string of `recordSize * 8` characters, split it into a character\n * array, reversed that, and mapped it to one number per *bit*; then per cell it sliced the\n * result again and summed `bit * Math.pow(2, index)`. Several arrays the length of the record\n * in bits, built and discarded for every row.\n *\n * Column-major is what makes the decode tight: a field's bit offset, width and bias are the\n * same for every row, so they are hoisted out of the loop and the inner loop does arithmetic\n * into a typed array and nothing else. Rows are assembled later, once, in `load()`.\n *\n * The window is what makes chunked iteration cheap: `decodeIndexColumn` walks records by\n * `base += recordSize`, so decoding rows k to k+n is a question of where the buffer slice starts\n * and how many iterations run. Nothing about the decoder changed to support it.\n *\n * Every index is checked as it is decoded. One that addresses neither a symbol of its field nor\n * NULL throws a `QvdCorruptedError` naming the file row (#125). Here and not where rows or columns\n * are built, because every read decodes through this method and a columnar read hands its codes\n * straight to the caller. Rows outside the window are not decoded, so they are not checked.\n *\n * @param {QvdRowWindow} window The rows to decode.\n * @param {number} [progressBase=0] Rows decoded before this call, so that progress over a chunked\n * iteration counts the whole window rather than restarting at every chunk - what `_buildRows` takes\n * for the same reason.\n * @param {number|null} [progressTotal=null] Rows the whole window covers, or null for this call's own.\n * @param {Array<Int32Array>|null} [into=null] Arrays to decode into, one per selected field and at least\n * `limit` long, for a caller that decodes chunk after chunk and keeps none of them. Null allocates.\n * @throws {QvdCorruptedError} If an index in the window addresses neither a symbol nor NULL.\n */\n async _parseIndexTable(window, progressBase = 0, progressTotal = null, into = null) {\n const {fields, recordSize, rowsToLoad, firstRow} = this._planIndexTable(window, 'parseIndexTable');\n\n // Rows decoded before this call, and rows the whole read covers, so an iteration's progress runs once\n // from nothing to its last row rather than restarting at every chunk - the rule `_buildRows` follows\n // for the `rows` stage, and what `iterate()` documents. A call that covers the whole read passes\n // neither and counts its own rows.\n const decodedBefore = progressBase;\n const decodedTotal = progressTotal === null ? rowsToLoad : progressTotal;\n\n // Every read parses the symbols before it decodes a row. The count checked against is the\n // parsed one, which still counts a symbol the two-pass path skipped: the parser keeps its place.\n assert(this._symbolTable, 'The QVD file symbol table has not been parsed.');\n const symbolTable = this._symbolTable;\n\n const decoders = fields.map((/** @type {any} */ field, /** @type {number} */ position) => ({\n bitOffset: headerInteger(field['BitOffset']),\n bitWidth: headerInteger(field['BitWidth']),\n bias: headerInteger(field['Bias']),\n symbolCount: symbolTable[position].numbers.length,\n name: field['FieldName'],\n }));\n // One array of codes per field. An iteration hands in the arrays it made for its first chunk and they\n // serve every chunk after it - the same size every time, and nothing keeps a chunk's codes once its\n // rows are built, since `_buildRows` copies the values out and the frame it yields holds only those.\n // A read that keeps its codes - `loadColumnar`, whose table is handed them - hands in nothing and gets\n // arrays of its own, which no later read can write over.\n const columns =\n into === null ? fields.map(() => new Int32Array(rowsToLoad)) : into.map((codes) => codes.subarray(0, rowsToLoad));\n\n // A slice of records at a time, every field decoded from it before the next is read, so the records\n // are read once however many fields there are. A damaged index is refused naming its file row, as\n // before, and the first refused is the first in the first slice that holds one, in field order\n // within the slice. A window whose records fit one slice - 16 MiB of them - reports exactly what it\n // did when each field was decoded in full before the next.\n await this._forEachSlice(firstRow, rowsToLoad, recordSize, (records, done, count) => {\n decoders.forEach((decoder, position) => {\n decodeIndexColumn(\n records,\n recordSize,\n count,\n decoder.bitOffset,\n decoder.bitWidth,\n decoder.bias,\n columns[position].subarray(done, done + count),\n {symbolCount: decoder.symbolCount, field: decoder.name, file: this._path, firstRow: firstRow + done},\n );\n });\n\n // Rows decoded, over the rows the read covers - a field at a time is no longer the unit of work.\n this._emitProgress('index-table', decodedBefore + done + count, decodedTotal);\n });\n\n if (rowsToLoad === 0) {\n this._emitProgress('index-table', decodedBefore, decodedTotal);\n }\n\n // Set together, once every column has decoded, so a chunk refused part-way leaves the reader\n // describing the chunk before it rather than a mix of the two.\n this._indexColumns = columns;\n this._rowsDecoded = rowsToLoad;\n }\n\n /**\n * Reads the file's schema and header metadata, without touching the symbol or index tables.\n *\n * Constant cost in the size of the file. `fromQvd(path, {maxRows: 0})` is not the same thing\n * and never was: the lazy path reads `headerEnd + symbolTableLength + rowsToLoad * recordSize`\n * bytes, so it still pulls the entire symbol table - 0.4MB on the taxi fixture, but hundreds\n * of megabytes on a high-cardinality file, and it has to be parsed as well as read.\n *\n * The memory check is deliberately not run for this. It sizes the rows a call will\n * materialise, and this materialises none; applying it would let a file too large to load\n * refuse to say what is in it.\n *\n * @return {Promise<import('./QvdDataFrame.js').QvdFileMetadata>} The file's schema and header.\n */\n async loadMetadata() {\n // A read like any other on this reader, one at a time: it parses the header into the state a read of\n // rows is using. It closes its own file before `_readData` returns, so `_closingAfter` has none to close.\n //\n // Deliberately without the checks `parseHeaderOnly` makes. `readMetadata()` describes a damaged file's\n // schema rather than refusing it - that is what it is for, and what the documentation promises - so\n // the two header reads differ in exactly that, and share what they build from the result.\n return await this._closingAfter(async () => {\n await this._readData({offset: 0, limit: null}, true);\n\n this._emitProgress('header', 0, 1);\n await this._parseHeader();\n this._emitProgress('header', 1, 1);\n this._throwIfAborted();\n\n return this.describeParsed();\n });\n }\n\n /**\n * The schema and header of the file this reader has parsed, as `readMetadata()` reports them.\n *\n * Built from the parsed header and nothing else, so a caller holding a header - a `QvdFile` - can have\n * it without reading the file a second time.\n *\n * @return {any} The metadata.\n */\n describeParsed() {\n assert(this._header && this._allFields, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n\n // The fields `_parseHeader` checked, which are the fields a read of rows reads: a header that\n // declares none, or a field with no name or another's, never gets this far.\n const columns = this._allFields.map((/** @type {any} */ field) => field['FieldName']);\n const rowCount = headerInteger(header['NoOfRecords']);\n\n // The same rule a load applies, through the same function. Coercing an unusable value to\n // zero here instead would report a damaged 606-row file as empty, and `rowCount` is exactly\n // what a caller is expected to branch on.\n validateRecordCount(rowCount, this._path, 'readMetadata');\n\n // An empty frame carrying the same header, so the camelCase mappings live in one place\n // rather than being spelled out a second time here and drifting from the ones a loaded\n // frame reports.\n const shape = new QvdDataFrame([], columns, header, {\n symbolTableBytes: headerInteger(header['Offset']),\n totalRows: rowCount,\n rowsLoaded: 0,\n symbolFiltering: false,\n symbolsKept: null,\n });\n\n return {\n columns,\n rowCount,\n columnCount: columns.length,\n fields: columns.map((/** @type {string} */ name) => shape.getFieldMetadata(name)),\n fileMetadata: shape.fileMetadata,\n metadata: header,\n };\n }\n\n /**\n * What a read of this file would cost, and whether it fits, without reading it.\n *\n * Reads the header and the file's size and nothing else, at the constant cost of `loadMetadata()`,\n * then asks the same question a read asks before it allocates anything - through the same function,\n * from the same numbers. That is the whole point: an answer computed a second way would be a second\n * opinion, and a read this approves would still be refused.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} [rawWindow]\n * The rows the read would cover, spelled any of the ways a read accepts.\n * @param {{chunkSize?: number|null}} [options] `chunkSize` when the read would be an `iterate()`,\n * which holds two chunks of rows rather than the window.\n * @return {Promise<any>} The answer - see `checkMemory`.\n */\n async checkRead(rawWindow, {chunkSize = null} = {}) {\n // Through the same function a read normalises its window with, so that a window this approves is\n // the window the read then resolves - and so that a malformed one is refused here with the message\n // it would be refused with there.\n const window = normaliseWindow(rawWindow, this._path);\n\n return await this._closingAfter(async () => {\n await this._parseHeaderChecked();\n\n return this.checkParsed(window, {chunkSize});\n });\n }\n\n /**\n * Reads this file's header, and nothing else, leaving it parsed on the reader.\n *\n * What `checkRead` and `QvdFile` both start with: the second asks many questions of one header, so the\n * read that produces it is separate from the questions. Every check a read makes before it trusts the\n * header's numbers is made here, so that nothing downstream has to wonder whether they hold.\n *\n * @return {Promise<void>} When the header is parsed and checked.\n */\n async parseHeaderOnly() {\n return await this._closingAfter(async () => await this._parseHeaderChecked());\n }\n\n /**\n * `parseHeaderOnly`'s body, for a caller already inside a read session - `checkRead` is one.\n *\n * @return {Promise<void>} When the header is parsed and checked.\n * @private\n */\n async _parseHeaderChecked() {\n await this._readData({offset: 0, limit: null}, true);\n\n // Bracketed as `loadMetadata` brackets it, so every entry point that reads only the header reports\n // the same stages to the same `onProgress`.\n this._emitProgress('header', 0, 1);\n await this._parseHeader();\n this._emitProgress('header', 1, 1);\n this._throwIfAborted();\n\n assert(\n this._header && this._selectedFields && this._allFields && this._symbolTableOffset !== null,\n 'The QVD file header has not been parsed.',\n );\n\n const header = this._header['QvdTableHeader'];\n const totalRows = headerInteger(header['NoOfRecords']);\n const recordSize = headerInteger(header['RecordByteSize']);\n const symbolTableLength = headerInteger(header['Offset']);\n\n // Before any arithmetic, the checks a read makes before it trusts these numbers - through the same\n // functions, so the same file is refused with the same message here as there.\n //\n // Without them a check answered a memory question about a file whose real problem is structural, and\n // answered it wrongly in both directions. A `NoOfRecords` of `606.5` or `6e2` made every figure\n // `NaN`, and `NaN` loses every comparison, so the answer came back `fits: true` for a read the\n // library then refused as corrupt - the false approval this whole API exists to rule out. A header\n // claiming 900 million rows in a 29 KB file came back `fits: false, reason: 'memory'` with a\n // 122 GB estimate and advice to read 25 million rows, and following that advice was refused as\n // corrupt too.\n validateRecordSize(recordSize, this._path, 'checkRead');\n validateRecordCount(totalRows, this._path, 'checkRead');\n\n // The header against the file on disk, which is what `_headerMatchesFile` records - set by the\n // header-only read for this reason. A read makes no memory claim about a file it does not\n // describe, and neither does this: the message is the one a windowed read gives for it.\n if (!this._headerMatchesFile) {\n throw new QvdCorruptedError('The file is shorter than its header claims.', {\n file: this._path,\n fileSize: this._fileSize,\n requiredBytes: this._symbolTableOffset + symbolTableLength + totalRows * recordSize,\n stage: 'checkRead',\n });\n }\n\n // And the field metadata, through the three functions the read uses on it. All of them read header\n // numbers and nothing else, so a check that stops at the header can still make every one of them -\n // and a check that skipped them approved four kinds of damage the read refuses: a field area past\n // the end of the symbol table, two fields claiming one area, a `Bias` that is neither 0 nor -2, and\n // a `BitWidth` past 31. Every one came back `fits: true` and was then a `QvdCorruptedError`.\n //\n // Every field, selected or not, for the reason the read gives: a projection must not turn a file a\n // full read refuses into one it accepts, and answering \"this fits\" about a file that does not\n // decode is the same mistake one step earlier.\n const tableLength = this._symbolTableLength();\n\n for (const field of this._allFields) {\n validateFieldMetadata(field, tableLength, this._path);\n validateFieldBitMetadata(field, recordSize, this._path);\n }\n\n validateSymbolAreas(this._allFields, this._path);\n }\n\n /**\n * What a read of the parsed header's file would cost, with no I/O at all.\n *\n * Separate from `checkRead` because a `QvdFile` asks this of one header many times - once per page a\n * viewer scrolls to - and the header is already in hand. `parseHeaderOnly` has to have run.\n *\n * @param {QvdRowWindow} window The rows the read would cover, normalised.\n * @param {{chunkSize?: number|null, fields?: Array<string>|null, materialisesRows?: boolean}} [options]\n * `chunkSize` for an `iterate()`; `fields` and `materialisesRows` to ask about a read other than the\n * one this reader was built for, which is what a `QvdFile` does per call.\n * @return {any} The answer - see `checkMemory`.\n */\n checkParsed(window, {chunkSize = null, fields = undefined, materialisesRows = undefined} = {}) {\n assert(this._header && this._allFields, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n const totalRows = headerInteger(header['NoOfRecords']);\n const recordSize = headerInteger(header['RecordByteSize']);\n const symbolTableLength = headerInteger(header['Offset']);\n const builds = materialisesRows === undefined ? this._materialisesRows : materialisesRows;\n\n // The caller's fields when it named some, this reader's otherwise. Selected here rather than taken\n // from `_selectedFields` so that one open file can be asked about different projections.\n const selected = selectFields(this._allFields, fields === undefined ? this._requestedFields : fields, this._path);\n\n const resolved = resolveWindow(window, totalRows);\n\n // The rows the read would really cover, which is what `_readFrom` hands the guard. Passing `null`\n // for a window with no `limit` ignored its `offset`, so `{offset: 600}` on a 606-row file was\n // sized as all 606 - the same read, estimated two different ways by the two halves that must agree.\n const windowRows = resolved.limit;\n const liveRows = chunkSize === null ? null : {rows: chunkSize * 2, perChunk: 2};\n const analysisAhead = this._analysisAhead(window, resolved, totalRows, symbolTableLength);\n\n // One measurement for every question asked below, the answer and each candidate selection alike.\n // Measured per call, each suggestion was sized against a slightly different budget from the answer\n // that prompted it, and a wide file paid for a heap-statistics call per column.\n const measured = getMemoryBudget();\n\n const ask = (/** @type {any} */ asked, /** @type {number|null} */ rows) => {\n const bytes = symbolBytesOf(this._fieldsHeldAfter(asked, this._allFields), symbolTableLength);\n const read = symbolBytesOf(this._fieldsReadBy(asked), symbolTableLength);\n const retained = symbolBytesOf(\n this._fieldsHeldAfter(asked, this._allFields).slice(asked.length),\n symbolTableLength,\n );\n\n return checkMemory({\n measured,\n symbolTableSize: bytes,\n maxRows: rows,\n totalRows,\n safetyFactor: this._memorySafetyFactor,\n columnCount: asked.length,\n materialisesRows: builds,\n live: liveRows,\n // A paging read keeps whole columns, so it is charged for whole columns - see `estimateMemoryUsage`.\n wholeSymbols: this._symbolCache !== null,\n retainedBytes: retained,\n bytesHeld: this._bytesHeld(read, rows, recordSize, liveRows, analysisAhead, bytes - retained),\n // What it reads from the file, which is not what it holds: the symbol areas it has still to read,\n // and every record the window covers, read a slice at a time and not kept - twice over where the\n // symbol-usage pass will run, since it reads them before the decode reads them again.\n readBytes: read + readPasses(analysisAhead) * windowRows * recordSize,\n });\n };\n\n const answer = ask(selected, windowRows);\n\n // The one suggestion `checkMemory` cannot make for itself: it is given what the selection costs\n // and never what each field costs. Offered only when dropping fields is something the caller can\n // actually do - more than one selected - and only after the smaller selection has been read back\n // through the check, like every other suggestion here.\n if (!answer.fits && selected.length > 1) {\n const bySize = [...selected].sort(\n (/** @type {any} */ a, /** @type {any} */ b) => headerInteger(a['Length']) - headerInteger(b['Length']),\n );\n\n for (let take = selected.length - 1; take >= 1; take -= 1) {\n const fewer = bySize.slice(0, take);\n\n if (ask(fewer, windowRows).fits) {\n answer.suggestions.push({\n option: 'fields',\n value: fewer.map((/** @type {any} */ field) => field['FieldName']),\n });\n break;\n }\n }\n }\n\n return answer;\n }\n\n /**\n * Loads the QVD file into memory and parses it.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} [window]\n * The rows to load. A number or null means what it always meant - the first N rows, or all of\n * them - and `{offset, limit}` is the same thing said more precisely, so `5` and\n * `{offset: 0, limit: 5}` are one read. `maxRows` is accepted as a second name for `limit`.\n * @throws {QvdValidationError} If the window is not a non-negative integer, null, or a valid\n * `{offset, limit}` object.\n * @return {Promise<QvdDataFrame>} The loaded QVD file.\n */\n async load(window = null) {\n const rows = normaliseWindow(window, this._path);\n\n return await this._closingAfter(async () => {\n const prepared = await this._prepare(rows);\n\n await this._parseIndexTable({offset: prepared.offset, limit: prepared.rowsAvailable});\n\n const data = this._buildRows(prepared.resolvedByField, 0, prepared.rowsAvailable);\n\n return new QvdDataFrame(\n data,\n prepared.columns,\n prepared.metadata,\n {\n ...prepared.loadStats,\n rowsLoaded: data.length,\n },\n prepared.storedSymbols,\n );\n });\n }\n\n /**\n * Reads the file as columns, without ever materialising rows.\n *\n * Shares every step with `load()` up to the point where rows would be built - see `_prepare`.\n * What it keeps instead is what the decoder already produced: one `Int32Array` of stored\n * indices per field, and one resolved value per distinct symbol. On the 1.7M x 20 taxi\n * fixture that is 133 MiB against the 352 MiB `data` retains, because a column costs four\n * bytes per row rather than a boxed value per cell, and the symbols are a few thousand\n * entries shared across every row that uses them. The codes' storage lives outside the V8\n * heap: 3 MiB of the 133 is on it.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} [window]\n * The rows to decode, in the same spellings `load()` accepts.\n * @return {Promise<import('./QvdColumnTable.js').QvdColumnTable>} The decoded columns.\n */\n async loadColumnar(window = null) {\n const rows = normaliseWindow(window, this._path);\n\n return await this._closingAfter(async () => {\n const prepared = await this._prepare(rows, null, true);\n\n await this._parseIndexTable({offset: prepared.offset, limit: prepared.rowsAvailable});\n\n // The table is built inside the read, not after it. `_closingAfter` lets the next read start the\n // moment it returns, and the import below is an `await`: a read beginning in that gap would decode\n // over `_indexColumns` and `_rowsDecoded` before this table had copied them, and the table would\n // carry this read's symbols and metadata with the other read's codes - the wrong values, thrown by\n // nothing. The file is closed once this returns; the table holds no part of it.\n const {QvdColumnTable} = await import('./QvdColumnTable.js');\n\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n return new QvdColumnTable({\n columns: prepared.columns,\n codesByField: this._indexColumns,\n symbolsByField: prepared.resolvedByField,\n halvesByField: prepared.halvesByField,\n rowCount: this._rowsDecoded,\n metadata: prepared.metadata,\n storedSymbols: prepared.storedSymbols,\n loadStats: {...prepared.loadStats, rowsLoaded: this._rowsDecoded},\n });\n });\n }\n\n /**\n * Yields the window as data frames of at most `chunkSize` rows.\n *\n * The file is opened, read and parsed **once**; only the index decode and the row building\n * happen per chunk. That is the whole reason this exists as a method rather than as a loop of\n * `load({offset, limit})` calls at the call site: the symbol table has to be parsed in full\n * whatever the chunk size - a stored index in the last chunk can address the first symbol -\n * and re-parsing it per chunk is what makes the obvious implementation cost more than a plain\n * load rather than less. PyQvd's chunked read does re-read it, and the comment on #140 records\n * that as a limitation rather than a design.\n *\n * What it bounds is row materialisation, which is what actually dominates a large read's heap.\n * Two chunks of rows are alive at a time, not one - `for await` keeps the yielded frame\n * reachable while this generator builds the next - which is why `liveRows` below is\n * `chunkSize * 2`, and why the heap it needs is twice what one chunk suggests.\n *\n * A window covering no rows yields nothing at all, rather than one empty frame - so\n * `for await` over an exhausted offset does nothing, which is what a paging loop wants. Its header\n * is still checked, as every read of a file's rows checks it.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} window\n * The rows to cover, in the same spellings `load()` accepts.\n * @param {number} chunkSize Rows per frame. Must be a positive integer.\n * @return {AsyncGenerator<QvdDataFrame>} The chunks, in order.\n */\n async *iterateRows(window, chunkSize) {\n requireChunkSize(chunkSize, this._path);\n\n // The memory guard sizes what is live at once, and from here that is *two* chunks rather than\n // the whole window. Passed into `_prepare` rather than stored on the reader, so it cannot\n // outlive this call: while it was an instance field, a reader used for `load()` after an\n // iteration would have the guard size two chunks for a read that materialises every row -\n // failing open, which is the uncatchable direction. No caller could reach that today, but\n // nothing said the reader was single-use either, and `QvdFileReader` is a documented export.\n // It is paired with the chunk size it came from so a refusal can recommend a chunk size rather\n // than a live-row count the caller has no knob for.\n //\n // Two, not one, because `for await (const chunk of ...)` keeps the yielded frame reachable\n // while the generator computes the next one - that is the async-iteration protocol, not\n // something this code can arrange away. Charging one chunk was measured and it was wrong in\n // the dangerous direction: on the 1.7M x 20 taxi fixture with `chunkSize: 500_000`, a read\n // that needs a 214MB heap was admitted at 170MB and the process aborted with a V8 heap-limit\n // abort - uncatchable, which is the exact failure the guard exists to prevent. Against the\n // measured minimum heap at four chunk sizes the two-chunk figure sits at 1.00 to 1.14x, never\n // below; the one-chunk figure sat at 0.53 to 0.61x.\n //\n // `estimateMemoryUsage` caps this at the window, so a window smaller than two chunks is still\n // charged only for itself.\n const liveRows = {rows: chunkSize * 2, perChunk: 2};\n\n const rows = normaliseWindow(window, this._path);\n\n // The file stays open from the first chunk to the last: each chunk's records are read when that\n // chunk is built, not all of them up front. It is closed however the iteration ends - after the\n // last chunk, when the caller stops early (`break` in a `for await` calls `return()`, which runs\n // the `finally`), or when a chunk is refused - with `_closeFile`'s rule that a failing close never\n // replaces the error already thrown. The read starts on the first `next()`, which runs this far\n // before it awaits anything, so a read started beside it is refused however soon it follows.\n this._startRead();\n\n let failing = false;\n\n try {\n const prepared = await this._prepare(rows, liveRows);\n\n // A window of no rows yields nothing, but the header is checked all the same. `load()` checks it\n // for `{limit: 0}`, because it plans an empty index table, and so does the two-pass path. The loop\n // below never runs for such a window, so it used to be the one read of a file's rows that let a\n // header every other read refuses - a Bias out of range, a BitWidth past 31 - go by unchecked.\n if (prepared.rowsAvailable === 0) {\n this._planIndexTable({offset: prepared.offset, limit: 0}, 'parseIndexTable');\n return;\n }\n\n // The codes of one chunk, made once and written over by every chunk after it. A chunk's rows are\n // built from them before the next chunk decodes, and the frame that is yielded holds the rows, so\n // nothing outlives the chunk it belongs to. Made here rather than per chunk because an iteration of\n // 83 million rows in chunks of 100,000 over twenty fields would otherwise make 830 sets of them, 8 MB\n // at a time, for buffers that never change size.\n const codes = prepared.columns.map(() => new Int32Array(Math.min(chunkSize, prepared.rowsAvailable)));\n\n for (let done = 0; done < prepared.rowsAvailable; done += chunkSize) {\n this._throwIfAborted();\n\n const count = Math.min(chunkSize, prepared.rowsAvailable - done);\n const offset = prepared.offset + done;\n\n await this._parseIndexTable({offset, limit: count}, done, prepared.rowsAvailable, codes);\n\n const data = this._buildRows(prepared.resolvedByField, done, prepared.rowsAvailable);\n\n // Every chunk shares the one record: the symbol table was parsed once, in full, for all of them.\n yield new QvdDataFrame(\n data,\n prepared.columns,\n prepared.metadata,\n {\n ...prepared.loadStats,\n offset,\n rowsLoaded: data.length,\n },\n prepared.storedSymbols,\n );\n }\n } catch (error) {\n failing = true;\n throw error;\n } finally {\n await this._endRead(failing);\n }\n }\n\n /**\n * Reads the file and resolves its symbols, stopping short of decoding any rows.\n *\n * Everything `load()`, `loadColumnar()` and `iterateRows()` have in common, which is everything\n * that depends on the file rather than on the window. Two read paths for one binary format is\n * the drift risk #113 is the standing example of - a stored index resolved one way here and\n * another way there returns plausible wrong values and throws nothing - so there is one path,\n * and the entry points differ only in what they do with what it returns and how many rows they\n * ask for at a time.\n *\n * @param {QvdRowWindow} window The rows the read covers.\n * @param {{rows: number, perChunk: number}|null} [liveRows] Rows held at one instant when that\n * is fewer than the window covers, and how many of them one row of the caller's chunk size\n * accounts for. Only `iterateRows` passes it; every other read holds what it covers.\n * @param {boolean} [wantHalves=false] Whether to keep both halves of each symbol of a field whose\n * cells do not show them, which only a columnar read has a use for.\n * @return {Promise<{columns: Array<string>, metadata: any, loadStats: any,\n * resolvedByField: Array<Array<any>>,\n * halvesByField: Array<import('./util/resolveSymbols.js').SymbolHalves|null>,\n * storedSymbols: import('./util/storedSymbols.js').StoredSymbols|null,\n * rowsAvailable: number, offset: number}>} The parsed file, with the window as it resolved\n * against it.\n * @private\n */\n async _prepare(window, liveRows = null, wantHalves = false) {\n this._throwIfAborted();\n\n await this._readData(window, false, liveRows);\n\n this._emitProgress('header', 0, 1);\n await this._parseHeader();\n this._emitProgress('header', 1, 1);\n this._throwIfAborted();\n\n assert(this._header, 'The QVD file header has not been parsed.');\n\n const totalRows = headerInteger(this._header['QvdTableHeader']['NoOfRecords']);\n const symbolTableLength = headerInteger(this._header['QvdTableHeader']['Offset']);\n\n // Where this window lands in this file. Resolved through the same function `_readData` used,\n // so the rows that were read and the rows that will be decoded cannot disagree.\n const resolved = resolveWindow(window, totalRows);\n const rowsAvailable = resolved.limit;\n\n // Determine if we should use two-pass symbol filtering\n // This optimization is beneficial for large symbol tables with limited row access\n let symbolsToKeep = null;\n let symbolsKept = null;\n\n // Which reads take the pass, and why, is in `_analysisWouldRun`. Asked through it rather than stated\n // here, because `_readData` has to ask the same question before the header is parsed to know what to\n // charge the memory guard, and one condition asked twice is one that drifts.\n // Never while paging: the pass decodes only what a window's rows use, and a cache of part of a\n // field is a cache that answers `undefined` for a row a later page asks about.\n if (this._analysisAhead(window, resolved, totalRows, symbolTableLength)) {\n // Pass 1: Analyze which symbols are actually needed\n symbolsToKeep = await this._analyzeIndexTableSymbolUsage({offset: resolved.offset, limit: rowsAvailable});\n\n // Recorded rather than logged. This used to be a console.log, which a library has no\n // business emitting: callers could not silence it, and it was the only way to find out\n // whether filtering had happened. It is now reported through QvdDataFrame.loadStats,\n // which callers can inspect - and tests can assert on deterministically, where the\n // previous test measured a heapUsed delta and failed on GC timing instead.\n symbolsKept = symbolsToKeep.reduce((sum, set) => sum + set.size, 0);\n }\n\n // Pass 2: Parse symbol table (with filtering if enabled)\n await this._parseSymbolTable(symbolsToKeep, rowsAvailable, liveRows);\n\n assert(this._symbolTable, 'The QVD file symbol table has not been parsed.');\n this._throwIfAborted();\n\n assert(this._selectedFields, 'The QVD file fields have not been resolved.');\n\n // Resolve each field's symbols once rather than once per cell.\n //\n // A stored index addresses the same symbol in every row, so what it reads as depends only on the\n // index. Doing it inside the row loop repeated it 34 million times on the taxi fixture for a\n // symbol table of a few thousand entries.\n //\n // A symbol the two-pass path did not decode has neither half and resolves to undefined here, and\n // no row of the window holds it. An index past the end of the array cannot reach this far: the\n // decode refuses it (#125), where it used to read as undefined too.\n //\n // A dual used to resolve to its text alone, so its number was unreachable and a write stored the\n // date as a string (#138). What it resolves to now depends on the `duals` option, and the half a\n // cell does not show goes into the stored-symbol record, which is what a write reads it back from.\n /** @type {Array<Array<any>>} */\n const resolvedByField = [];\n /** @type {Array<import('./util/resolveSymbols.js').SymbolHalves|null>} */\n const halvesByField = [];\n /** @type {Array<import('./util/storedSymbols.js').StoredSymbolsEntry>} */\n const entries = [];\n\n this._symbolTable.forEach((symbols, position) => {\n const {values, entry, halves} = resolveFieldSymbols(\n symbols,\n // @ts-ignore - asserted above\n this._selectedFields[position]['FieldName'],\n this._duals,\n this._coerceNumericStrings,\n wantHalves,\n );\n\n resolvedByField.push(values);\n halvesByField.push(halves);\n\n if (entry !== null) {\n entries.push(entry);\n }\n });\n\n const columns = this._selectedFields.map((/** @type {any} */ field) => field['FieldName']);\n\n // The complete header metadata, describing the *file* rather than this read of it.\n //\n // Not narrowed to the selected fields, and not adjusted for the window. `NoOfRecords` has\n // always been the file's row count rather than the number loaded - that is what `loadStats`\n // is for - and `select()` has always passed the whole header through to the frame it returns,\n // so narrowing here would give one answer for a projection made at load time and another for\n // the same projection made afterwards.\n const metadata = this._header['QvdTableHeader'];\n\n // Null rather than an empty record when every cell shows its whole symbol, which is the common case\n // for a file without duals. The record is also left on the header object, not enumerably, so a frame\n // built as `new QvdDataFrame(data, columns, df.metadata)` keeps it.\n const storedSymbols = entries.length > 0 ? trustStoredSymbols(entries) : null;\n\n if (storedSymbols !== null) {\n attachStoredSymbols(metadata, storedSymbols);\n }\n\n /** @type {import('./QvdDataFrame.js').QvdLoadStats} */\n const loadStats = {\n symbolTableBytes: symbolTableLength,\n totalRows,\n rowsLoaded: 0,\n offset: resolved.offset,\n symbolFiltering: symbolsToKeep !== null,\n symbolsKept,\n };\n\n return {\n columns,\n metadata,\n loadStats,\n resolvedByField,\n halvesByField,\n storedSymbols,\n rowsAvailable,\n offset: resolved.offset,\n };\n }\n\n /**\n * Builds rows from the columns currently decoded.\n *\n * `data` stays eager: of the four ways this library is used - a full read, a preview already\n * bounded by a limit, writing an array out, and reading metadata - not one is helped by\n * materialising a row only when it is touched, and a lazy accessor would cost a proxy, a cache\n * and mutation semantics to serve none of them. A caller who wants columns without paying for\n * rows uses `QvdColumnTable`, which stops before this loop.\n *\n * @param {Array<Array<any>>} resolvedByField One resolved value per distinct symbol, per field.\n * @param {number} progressBase Rows already delivered before this call, so that progress over a\n * chunked iteration counts the whole window rather than restarting at every chunk.\n * @param {number} progressTotal Rows the whole window covers.\n * @return {Array<Array<any>>} The rows.\n * @private\n */\n _buildRows(resolvedByField, progressBase, progressTotal) {\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n const indexColumns = this._indexColumns;\n const fieldCount = indexColumns.length;\n const rowCount = this._rowsDecoded;\n const data = new Array(rowCount);\n\n // Report about once per percent of the window, as the writer does, and at least once at the\n // end. Checking the abort signal on the same tick keeps a cancelled 20-million-row load from\n // running to completion before it notices.\n const reportInterval = Math.max(1, Math.floor(progressTotal / 100));\n\n for (let row = 0; row < rowCount; row++) {\n const values = new Array(fieldCount);\n\n for (let field = 0; field < fieldCount; field++) {\n const symbolIndex = indexColumns[field][row];\n\n // A negative index is how a bias of -2 encodes NULL: stored index 0 means NULL, and\n // real symbols start at 2. It addresses no symbol. The decode has refused every other\n // index that addresses nothing, so a non-negative one is always inside the array.\n values[field] = symbolIndex < 0 ? null : resolvedByField[field][symbolIndex];\n }\n\n data[row] = values;\n\n if ((progressBase + row + 1) % reportInterval === 0 || row + 1 === rowCount) {\n this._throwIfAborted();\n this._emitProgress('rows', progressBase + row + 1, progressTotal);\n }\n }\n\n return data;\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {normaliseWindow, readerOptionsFrom, requireChunkSize, windowFrom} from './util/readOptions.js';\n\n/**\n * A QVD file opened for paging: its header read once, and read from a page at a time.\n *\n * Every other entry point is one read from start to finish - open the file, read the header, parse the\n * symbols it needs, build the result, close. A viewer showing a hundred rows at a time pays the header\n * and the symbol parse again on every page, and `iterate()` is no answer either: it goes forwards only,\n * so it cannot jump to row five million and it cannot go back.\n *\n * ```js\n * const qvd = await QvdDataFrame.open('sales.qvd', {allowedDir: '/data'});\n *\n * qvd.metadata; // read once, when it opened\n * const answer = qvd.check({offset: 0, limit: 100}); // no I/O at all: the header is already here\n * const page = await qvd.rows({offset: 5_000_000, limit: 100});\n *\n * await qvd.close();\n * ```\n *\n * The header is read once, and so is each column: a column decoded for one page is kept for the pages\n * after it, and neither its bytes nor its values are read again. On a 300,000-row file with a\n * 50,000-value text column, pages settled at about 2 ms against about 13 ms for the same window through\n * `fromQvd()`. The first page costs about what a single read costs; it is the ones after it that are\n * cheap.\n *\n * Each page still opens the file, and a first touch still decodes a whole column rather than only as\n * far as the page needs - see the issue for both.\n *\n * Calls are serialised, in the order they were made, so a viewer can ask for the next page without\n * awaiting the one before it. That is this class's job rather than the reader's: a `QvdFileReader`\n * refuses a second read while one is under way, and serialising here means it never sees two.\n */\nexport class QvdFile {\n /**\n * Not called directly - `QvdDataFrame.open()` is the way in, because a `QvdFile` is only ever a file\n * whose header has been read, and a constructor cannot wait for that.\n *\n * @param {any} reader The reader holding the parsed header.\n * @param {any} metadata What `readMetadata()` returns for this file.\n * @param {any} options The options the file was opened with.\n * @private\n */\n constructor(reader, metadata, options) {\n this._reader = reader;\n this._metadata = metadata;\n this._options = options;\n this._closed = false;\n\n /**\n * The tail of the queue: every call chains onto it, so they run one at a time and in order.\n *\n * It absorbs failures - `.then(ignore, ignore)` - because a page that throws must not stop the pages\n * behind it. A viewer that asks for a row past the end of the file should get that one refusal, not\n * a dead file.\n */\n this._tail = Promise.resolve();\n\n /**\n * The readers the pages go through, one per shape, each keeping what it has decoded.\n *\n * Built on the first page of that shape rather than at `open()`, because a file may only ever be\n * asked for rows, or only for columns, and a reader that decodes nothing is a reader nobody needed.\n */\n this._readers = {rows: null, columns: null};\n }\n\n /**\n * The file's header and schema, as `QvdDataFrame.readMetadata()` returns them.\n *\n * Read when the file was opened, so this costs nothing and cannot fail.\n *\n * @return {any} The metadata.\n */\n get metadata() {\n return this._metadata;\n }\n\n /**\n * Whether `close()` has been called.\n *\n * @return {boolean} True once it has.\n */\n get closed() {\n return this._closed;\n }\n\n /**\n * What a read of this file would cost, and whether it fits - with no I/O at all.\n *\n * The same answer `QvdDataFrame.checkRead()` gives, from the header this file already holds, so a\n * viewer can size a page before asking for it without touching the disk.\n *\n * @param {{offset?: number, limit?: number|null, maxRows?: number|null, fields?: Array<string>|null,\n * as?: 'rows'|'columns', chunkSize?: number|null}} [options] The read being asked about - the same\n * bag `rows()` takes, plus `as` and `chunkSize` to say which shape of read it is.\n * @return {any} The answer - `fits`, `reason`, `estimate`, `budget`, `exact`, `suggestions`.\n * @throws {QvdValidationError} If the file is closed, or an option's value is not valid.\n */\n check(options = {}) {\n this._refuseWhenClosed('check');\n\n const {as = 'rows', chunkSize = null} = options;\n\n if (as !== 'rows' && as !== 'columns') {\n throw new QvdValidationError(\"as must be 'rows' or 'columns'\", {\n provided: as,\n reason: 'option',\n option: 'as',\n value: as,\n file: this._options.path,\n });\n }\n\n if (chunkSize !== null) {\n requireChunkSize(chunkSize, this._options.path);\n }\n\n // Asked of the reader that would make this page, not of the one holding the header: once a page of\n // this shape has been read, that reader is holding decoded columns, and they are part of what the\n // next page costs. Asked of the header reader, a warm file answered as though it were cold - the\n // check and the read disagreeing about the same page, which is the one thing this answer must not\n // do. Before any page of that shape there is no such reader and no cache, and the header reader is\n // the right one.\n const reader = this._readers[as] ?? this._reader;\n\n return reader.checkParsed(normaliseWindow(windowFrom(options), this._options.path), {\n chunkSize,\n // Resolved here rather than left to the reader, exactly as `_page` resolves it. A warm reader is\n // still holding the last page's selection, and `checkParsed` falls back to it - so a `check()`\n // naming no fields answered for whatever the previous page happened to name. On a four-column\n // file after a page naming one of them, it reported 27,490 bytes for a read that costs 108,160:\n // understating, which is the direction that approves a read the read then refuses.\n fields: options.fields === undefined ? (this._options.fields ?? null) : options.fields,\n materialisesRows: as === 'rows',\n });\n }\n\n /**\n * Reads a page of rows.\n *\n * @param {{offset?: number, limit?: number|null, maxRows?: number|null, fields?: Array<string>|null,\n * onProgress?: Function, signal?: AbortSignal}} [options] The page, and how to read it. One bag,\n * as every other entry point takes: `offset` and `limit` say which rows, `fields` names a projection\n * for this page alone, and anything left out falls back to what the file was opened with.\n * @return {Promise<any>} The page, as a `QvdDataFrame`.\n * @throws {QvdValidationError} If the file is closed.\n */\n async rows(options = {}) {\n this._refuseWhenClosed('rows');\n\n return await this._serialised(async () => await this._page(options, true, (reader, window) => reader.load(window)));\n }\n\n /**\n * Reads a page as columns, building no rows.\n *\n * @param {{offset?: number, limit?: number|null, maxRows?: number|null, fields?: Array<string>|null,\n * onProgress?: Function, signal?: AbortSignal}} [options] The page, as `rows()` takes it.\n * @return {Promise<any>} The page, as a `QvdColumnTable`.\n * @throws {QvdValidationError} If the file is closed.\n */\n async columns(options = {}) {\n this._refuseWhenClosed('columns');\n\n return await this._serialised(\n async () => await this._page(options, false, (reader, window) => reader.loadColumnar(window)),\n );\n }\n\n /**\n * Closes the file.\n *\n * Every call after it is refused with `reason: 'closed'`. Calling it twice is not an error: a\n * `finally` that closes and an `await using` that closes are both right, and both may run.\n *\n * @return {Promise<void>} When the pages already in flight have finished.\n */\n async close() {\n if (this._closed) {\n return;\n }\n\n this._closed = true;\n\n // The pages already queued still run: they were asked for while the file was open, and a page that\n // was going to arrive should arrive. What `closed` stops is asking for another.\n await this._tail;\n\n // And then the columns they decoded go. `close()` is the caller saying they are done with the file,\n // and a closed file that still holds every column any page touched is holding the memory closing it\n // was meant to release - which on the files this exists for is gigabytes, for as long as anything\n // keeps the object.\n for (const reader of Object.values(this._readers)) {\n reader?.endPaging();\n }\n\n this._readers = {rows: null, columns: null};\n this._reader.endPaging();\n this._reader = null;\n }\n\n /**\n * `await using` support, where the runtime has it.\n *\n * @return {Promise<void>} When closed.\n */\n async [Symbol.asyncDispose]() {\n await this.close();\n }\n\n /**\n * Refuses a call on a closed file, in the vocabulary the rest of the API uses.\n *\n * @param {string} call The method the caller reached for, for the error.\n * @private\n */\n _refuseWhenClosed(call) {\n if (this._closed) {\n throw new QvdValidationError('The file is closed: open it again to read from it', {\n reason: 'closed',\n call,\n file: this._options.path,\n });\n }\n }\n\n /**\n * Runs `work` after everything asked for before it, and before everything asked for after.\n *\n * @param {() => Promise<any>} work The page to read.\n * @return {Promise<any>} Its result.\n * @private\n */\n async _serialised(work) {\n const run = this._tail.then(work, work);\n\n // Failures are absorbed from the *queue*, not from the caller: `run` is what the caller awaits and\n // still rejects, while the tail carries on so one refused page does not refuse every page behind it.\n this._tail = run.then(\n () => undefined,\n () => undefined,\n );\n\n return await run;\n }\n\n /**\n * Reads one page, through the reader that keeps what the pages before it decoded.\n *\n * One reader for every page rather than one per page, which is what makes the symbol cache possible:\n * decoding the symbols is 72% of a page of a hundred rows from a 300,000-row file, and a reader built\n * fresh each time did all of it again. Two readers, because a columnar page builds no rows and a row\n * page does, and `materialisesRows` is fixed when a reader is constructed - so each shape keeps its\n * own, and its own cache.\n *\n * Options that belong to one call rather than to the file - the fields this page alone wants, and the\n * `onProgress` and `signal` watching it - are told to that shared reader for the next read and no\n * further. A page naming one of them used to build a reader of its own instead, which quietly turned\n * the cache off and the two-pass symbol path on: watching a page changed what the page did.\n *\n * @param {any} options What the call passed.\n * @param {boolean} builds Whether the page materialises rows.\n * @param {(reader: any, window: any) => Promise<any>} read The read to make.\n * @return {Promise<any>} The page.\n * @private\n */\n async _page(options, builds, read) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const kept = builds ? 'rows' : 'columns';\n\n if (!this._readers[kept]) {\n const reader = new QvdFileReader(this._options.path, {\n ...readerOptionsFrom(this._options),\n materialisesRows: builds,\n });\n\n reader.beginPaging();\n this._readers[kept] = reader;\n }\n\n const reader = this._readers[kept];\n\n // The file's fields unless this page names its own, which is what the API proposal settled on:\n // both, with the file's as the default.\n reader.selectForNextRead(options.fields === undefined ? (this._options.fields ?? null) : options.fields);\n\n // And this page's watchers, which belong to one call. A page naming either used to get a reader of\n // its own - so passing a progress callback silently turned the cache off and the two-pass symbol\n // path on, changing what the read did rather than only observing it.\n reader.observeNextRead({\n onProgress: options.onProgress ?? this._options.onProgress,\n signal: options.signal ?? this._options.signal,\n });\n\n return await read(reader, windowFrom(options));\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {asDual, describeType, isPlainObject} from './util/cellRules.js';\nimport {metadataOptionsFrom, readerOptionsFrom, requireChunkSize, windowFrom} from './util/readOptions.js';\nimport {\n STORED_SYMBOLS,\n attachStoredSymbols,\n narrowStoredSymbols,\n normaliseStoredSymbols,\n storedSymbolsEntry,\n storedTextOf,\n} from './util/storedSymbols.js';\n\n/**\n * @typedef {Object} QvdNumberFormat\n * @property {string} Type - Number format type\n * @property {string} nDec - Number of decimals\n * @property {string} UseThou - Use thousands separator\n * @property {string} Fmt - Format string\n * @property {string} Dec - Decimal separator\n * @property {string} Thou - Thousands separator\n */\n\n/**\n * @typedef {Object} QvdFieldHeader\n * @property {string} FieldName - The name of the field\n * @property {string|number} [BitOffset] - The bit offset\n * @property {string|number} [BitWidth] - The bit width\n * @property {string|number} [Bias] - The bias value\n * @property {string|number} [NoOfSymbols] - Number of symbols\n * @property {string|number} [Offset] - The offset\n * @property {string|number} [Length] - The length\n * @property {string} [Comment] - Field comment\n * @property {QvdNumberFormat|string} [NumberFormat] - Number format\n * @property {Object|string} [Tags] - Field tags\n */\n\n/**\n * @typedef {Object} QvdFields\n * @property {QvdFieldHeader|QvdFieldHeader[]} QvdFieldHeader - Field header(s)\n */\n\n/**\n * @typedef {Object} QvdMetadata\n * @property {string|number} [QvBuildNo] - QlikView build number\n * @property {string} [CreatorDoc] - Creator document\n * @property {string} [CreateUtcTime] - Creation UTC time\n * @property {string} [SourceCreateUtcTime] - Source creation UTC time\n * @property {string} [SourceFileUtcTime] - Source file UTC time\n * @property {string|number} [SourceFileSize] - Source file size\n * @property {string} [StaleUtcTime] - Stale UTC time\n * @property {string} [TableName] - Table name\n * @property {string|number} [NoOfRecords] - Number of records\n * @property {string|number} [RecordByteSize] - Record byte size\n * @property {string|number} [Offset] - Offset\n * @property {string|number} [Length] - Length\n * @property {string} [Compression] - Compression type\n * @property {string} [Comment] - Comment\n * @property {string} [EncryptionInfo] - Encryption info\n * @property {string} [TableTags] - Table tags\n * @property {string} [ProfilingData] - Profiling data\n * @property {Object|string} [Lineage] - Lineage\n * @property {QvdFields} [Fields] - Fields information\n */\n\n/**\n * A QVD file's schema and header, read without its data.\n *\n * @typedef {Object} QvdFileMetadata\n * @property {Array<string>} columns Field names, in file order.\n * @property {number} rowCount Rows the file declares in its header. Note that this is the\n * file's row count, not a number of rows loaded - nothing was loaded.\n * @property {number} columnCount Number of fields.\n * @property {Array<Object|null>} fields Per-field metadata, in the same shape and order that\n * `getFieldMetadata()` returns for a loaded frame.\n * @property {Object} fileMetadata File-level metadata, in the same shape as the `fileMetadata`\n * accessor on a loaded frame.\n * @property {QvdMetadata} metadata The raw `QvdTableHeader`, as `metadata` gives it.\n */\n\n/**\n * Statistics describing the read that produced a data frame.\n *\n * @typedef {Object} QvdLoadStats\n * @property {number} symbolTableBytes Size of the file's symbol table, in bytes.\n * @property {number} totalRows Rows the file declares in its header.\n * @property {number} rowsLoaded Rows actually materialised.\n * @property {number} [offset] File row the first materialised row came from: zero unless the read\n * asked for a window, the window's start when it did, and under `iterate()` the chunk's own\n * position - which is the only way a chunk can say where in the file it sits. An offset past the\n * end of the file reports the clamped value, so it equals `totalRows` for a window that caught\n * no rows.\n * @property {boolean} symbolFiltering Whether the two-pass symbol-filtering path was used.\n * @property {number|null} symbolsKept Symbols retained by that path, or null when it did not run.\n */\n\n/**\n * @typedef {import('./util/storedSymbols.js').StoredSymbols} QvdStoredSymbols\n */\n\n/**\n * A data frame in a form that survives `JSON`, `structuredClone`, `postMessage` and `v8.serialize`,\n * and that `fromDict` turns back into a frame writing the same symbols.\n *\n * @typedef {Object} QvdDataFrameDict\n * @property {Array<string>} columns The columns.\n * @property {Array<Array<any>>} data The rows.\n * @property {QvdMetadata|null} [metadata] The header, or null.\n * @property {QvdStoredSymbols|null} [storedSymbols] The stored-symbol record, or null.\n */\n\n/**\n * The header entry `toQvd` writes for a field nobody has described.\n *\n * @param {string} fieldName The field.\n * @return {Object} A field header with no comment, no tags and an UNKNOWN number format.\n */\nfunction defaultFieldHeader(fieldName) {\n return {\n FieldName: fieldName,\n BitOffset: 0,\n BitWidth: 0,\n Bias: 0,\n NoOfSymbols: 0,\n Offset: 0,\n Length: 0,\n Comment: '',\n NumberFormat: {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: {},\n };\n}\n\n/**\n * The header a metadata setter starts from on a frame that has none - one built by `fromDict`, or by\n * the constructor without metadata.\n *\n * @param {Array<string>} columns The frame's columns.\n * @return {QvdMetadata} A header describing every column and nothing else.\n */\nfunction defaultHeader(columns) {\n return {\n QvBuildNo: 50667,\n CreatorDoc: '',\n CreateUtcTime: '',\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: '',\n Fields: {\n QvdFieldHeader: columns.map(defaultFieldHeader),\n },\n NoOfRecords: 0,\n RecordByteSize: 0,\n Offset: 0,\n Length: 0,\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {},\n };\n}\n\n/**\n * Represents a loaded QVD file.\n */\nexport class QvdDataFrame {\n /**\n * Represents the data frame stored inside a QVD file.\n *\n * The record is resolved once, here: the fifth argument when given, otherwise the one a read left on\n * its header object, so `new QvdDataFrame(data, columns, df.metadata)` keeps what `df` would write.\n * Either is narrowed to `columns`. An entry for a field the frame does not have describes no cell it\n * holds, and would make the frame's own `toDict()` a dictionary `fromDict` refuses - which is what a\n * header's record did for a frame built from some of a read's columns.\n *\n * @param {Array<Array<any>>} data The data of the data frame.\n * @param {Array<string>} columns The columns of the data frame.\n * @param {QvdMetadata|null} metadata The metadata from the QVD file header (optional).\n * @param {QvdLoadStats|null} loadStats Statistics about the read (optional).\n * @param {QvdStoredSymbols|null} storedSymbols What the frame's cells were read from, where a cell\n * shows only one half of its symbol (optional) - see `storedSymbols`.\n * @throws {QvdValidationError} If the record is malformed.\n */\n constructor(data, columns, metadata = null, loadStats = null, storedSymbols = null) {\n this._data = data;\n this._columns = columns;\n this._metadata = metadata;\n /** Whether `_metadata` is this frame's own to change - see `_ownMetadata`. */\n this._ownsMetadata = false;\n this._loadStats = loadStats;\n /** @type {QvdStoredSymbols|null} */\n this._storedSymbols = narrowStoredSymbols(\n normaliseStoredSymbols(\n // @ts-ignore - a symbol-keyed property the reader defines on the header object\n storedSymbols ?? (metadata !== null && typeof metadata === 'object' ? metadata[STORED_SYMBOLS] : null),\n ),\n columns,\n );\n }\n\n /**\n * Returns the data of the data frame.\n */\n get data() {\n return this._data;\n }\n\n /**\n * Returns the columns of the data frame.\n */\n get columns() {\n return this._columns;\n }\n\n /**\n * Returns the shape of the data frame.\n */\n get shape() {\n return [this._data.length, this._columns.length];\n }\n\n /**\n * Returns the complete metadata object from the QVD file header.\n * @return {Object|null} The complete metadata object or null if not available.\n */\n get metadata() {\n return this._metadata;\n }\n\n /**\n * What the frame's cells were read from, where a cell shows only one half of its symbol.\n *\n * A dual read as its number has a text the cell does not show; one read as its text has a number;\n * a string read as a number has the text it was spelled with. The record keeps those halves, per\n * field, keyed by the value the cell holds, so `toQvd` writes the symbols the frame was read from\n * and `textAt` can return any cell's text. It moves with the frame through `head`, `tail`, `rows`,\n * `select`, `toDict` and `fromDict`.\n *\n * Frozen plain data: `[{field, values, numbers, texts}]`, where a cell holding `values[i]` stands for\n * the stored symbol (`numbers[i]`, `texts[i]`), a null number meaning a pure string and a null text a\n * pure number.\n *\n * @return {QvdStoredSymbols|null} The record, or null when the frame has none: every cell of the read\n * showed its whole symbol, or the frame was built without one. A frame whose columns have no entry\n * in the record it was given or found - one from `select`, or one built from some of a read's\n * columns and its header - has an empty record rather than null, because a frame given null takes\n * the record its header carries, which describes every field of the read.\n */\n get storedSymbols() {\n return this._storedSymbols;\n }\n\n /**\n * Returns statistics about the read that produced this data frame.\n *\n * Carried by every frame that came from a file - `fromQvd()`, and each chunk `iterate()` yields,\n * which is how a chunk reports its `offset`. `fromDict()`, `head()`, `tail()`, `rows()` and\n * `select()` describe no particular read and report null rather than a stale figure.\n *\n * The main use is confirming that a lazy load actually filtered the symbol table:\n * `symbolFiltering` says whether the two-pass path ran, and `symbolsKept` how many symbols\n * survived it. Note that a bounded read does not filter on its own - the two-pass path engages\n * only above `symbolFilteringThreshold`, so on a file below it this reports false and every\n * symbol was parsed however few rows were asked for.\n *\n * @return {QvdLoadStats|null} Load statistics, or null if this frame did not come from a file.\n */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * Returns file-level metadata from the QVD header.\n * @return {Object} File-level metadata properties.\n */\n get fileMetadata() {\n if (!this._metadata) {\n return {};\n }\n\n const header = this._metadata;\n return {\n qvBuildNo: header.QvBuildNo,\n creatorDoc: header.CreatorDoc,\n createUtcTime: header.CreateUtcTime,\n sourceCreateUtcTime: header.SourceCreateUtcTime,\n sourceFileUtcTime: header.SourceFileUtcTime,\n sourceFileSize: header.SourceFileSize,\n staleUtcTime: header.StaleUtcTime,\n tableName: header.TableName,\n noOfRecords: header.NoOfRecords,\n recordByteSize: header.RecordByteSize,\n offset: header.Offset,\n length: header.Length,\n compression: header.Compression,\n comment: header.Comment,\n encryptionInfo: header.EncryptionInfo,\n tableTags: header.TableTags,\n profilingData: header.ProfilingData,\n lineage: header.Lineage,\n };\n }\n\n /**\n * Returns field-level metadata for a specific field/column.\n * @param {string} fieldName The name of the field.\n * @return {Object|null} Field metadata or null if field not found.\n */\n getFieldMetadata(fieldName) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return null;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const field = fields.find((f) => f.FieldName === fieldName);\n if (!field) {\n return null;\n }\n\n return {\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n };\n }\n\n /**\n * Returns field-level metadata for all fields.\n * @return {Array<Object>} Array of field metadata objects.\n */\n getAllFieldMetadata() {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return [];\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n return fields.map((field) => ({\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n }));\n }\n\n /**\n * @typedef {Object} FileMetadataUpdate\n * @property {string|number} [qvBuildNo] - QlikView build number\n * @property {string} [creatorDoc] - Creator document\n * @property {string} [createUtcTime] - Creation UTC time\n * @property {string} [sourceCreateUtcTime] - Source creation UTC time\n * @property {string} [sourceFileUtcTime] - Source file UTC time\n * @property {string|number} [sourceFileSize] - Source file size\n * @property {string} [staleUtcTime] - Stale UTC time\n * @property {string} [tableName] - Table name\n * @property {string} [compression] - Compression type\n * @property {string} [comment] - Comment\n * @property {string} [encryptionInfo] - Encryption info\n * @property {string} [tableTags] - Table tags\n * @property {string} [profilingData] - Profiling data\n * @property {Object|string} [lineage] - Lineage\n */\n\n /**\n * The header a metadata setter may change: this frame's own.\n *\n * A frame's header can be shared. `head`, `tail`, `rows` and `select` pass theirs on, every chunk\n * `iterate()` yields holds the same one, and `fromDict` uses the object it is given. So the first\n * change copies it, and a change made through one frame never reaches another. A frame with no header\n * gets the one `toQvd` would write for it. The copy keeps the stored-symbol record the header carries,\n * so `new QvdDataFrame(data, columns, df.metadata)` still writes what `df` would.\n *\n * @return {any} The header.\n */\n _ownMetadata() {\n if (!this._metadata) {\n this._metadata = defaultHeader(this._columns);\n } else if (!this._ownsMetadata) {\n // @ts-ignore - a symbol-keyed property the reader defines on the header object\n const record = this._metadata[STORED_SYMBOLS];\n this._metadata = structuredClone(this._metadata);\n if (record) {\n attachStoredSymbols(this._metadata, record);\n }\n }\n this._ownsMetadata = true;\n return this._metadata;\n }\n\n /**\n * Sets modifiable file-level metadata. Immutable properties related to data storage are ignored.\n *\n * The change applies to this frame only, never to a frame it was derived from or shares a header\n * with.\n *\n * @param {FileMetadataUpdate} metadata Object containing metadata properties to update.\n */\n setFileMetadata(metadata) {\n const header = this._ownMetadata();\n\n // Only allow modification of certain fields (not Offset, Length, NoOfRecords, RecordByteSize)\n const modifiableFields = [\n 'qvBuildNo',\n 'creatorDoc',\n 'createUtcTime',\n 'sourceCreateUtcTime',\n 'sourceFileUtcTime',\n 'sourceFileSize',\n 'staleUtcTime',\n 'tableName',\n 'compression',\n 'comment',\n 'encryptionInfo',\n 'tableTags',\n 'profilingData',\n 'lineage',\n ];\n\n // Map camelCase to XML property names\n const fieldMapping = {\n qvBuildNo: 'QvBuildNo',\n creatorDoc: 'CreatorDoc',\n createUtcTime: 'CreateUtcTime',\n sourceCreateUtcTime: 'SourceCreateUtcTime',\n sourceFileUtcTime: 'SourceFileUtcTime',\n sourceFileSize: 'SourceFileSize',\n staleUtcTime: 'StaleUtcTime',\n tableName: 'TableName',\n compression: 'Compression',\n comment: 'Comment',\n encryptionInfo: 'EncryptionInfo',\n tableTags: 'TableTags',\n profilingData: 'ProfilingData',\n lineage: 'Lineage',\n };\n\n modifiableFields.forEach((field) => {\n // @ts-ignore - Dynamic property access for metadata mapping\n if (metadata[field] !== undefined) {\n // @ts-ignore - Dynamic property access for metadata mapping\n header[fieldMapping[field]] = metadata[field];\n }\n });\n }\n\n /**\n * @typedef {Object} FieldMetadataUpdate\n * @property {string} [comment] - Field comment\n * @property {QvdNumberFormat|string} [numberFormat] - Number format\n * @property {Object|string} [tags] - Field tags\n */\n\n /**\n * Sets modifiable field-level metadata for a specific field.\n * Immutable properties related to data storage (Offset, Length, BitOffset, etc.) are ignored.\n *\n * Works on any frame, including one with no header yet - one from `fromDict` - and on a column the\n * header does not describe. The change applies to this frame only, never to a frame it was derived\n * from or shares a header with.\n *\n * @param {string} fieldName The name of the field.\n * @param {FieldMetadataUpdate} metadata Object containing field metadata properties to update.\n * @throws {QvdValidationError} If the frame has no column of that name.\n */\n setFieldMetadata(fieldName, metadata) {\n if (!this._columns.includes(fieldName)) {\n throw new QvdValidationError(`Column '${fieldName}' does not exist`, {\n column: fieldName,\n availableColumns: this._columns,\n });\n }\n\n const header = this._ownMetadata();\n if (!header.Fields || typeof header.Fields !== 'object' || !header.Fields.QvdFieldHeader) {\n header.Fields = {QvdFieldHeader: []};\n }\n\n let fields = header.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n header.Fields.QvdFieldHeader = fields;\n }\n\n let field = fields.find((/** @type {any} */ f) => f.FieldName === fieldName);\n if (!field) {\n field = defaultFieldHeader(fieldName);\n fields.push(field);\n }\n\n // Only allow modification of Comment, NumberFormat, and Tags (not Offset, Length, BitOffset, etc.)\n if (metadata.comment !== undefined) {\n field.Comment = metadata.comment;\n }\n if (metadata.numberFormat !== undefined) {\n field.NumberFormat = metadata.numberFormat;\n }\n if (metadata.tags !== undefined) {\n field.Tags = metadata.tags;\n }\n }\n\n /**\n * Returns the first n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n head(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('head() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(this._data.slice(0, n), this._columns, this._metadata, null, this._storedSymbols);\n }\n\n /**\n * Returns the last n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n tail(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('tail() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(\n n === 0 ? [] : this._data.slice(-n),\n this._columns,\n this._metadata,\n null,\n this._storedSymbols,\n );\n }\n\n /**\n * Returns the selected rows of the data frame.\n *\n * @param {...number} args The indices of the rows to return.\n * @return {QvdDataFrame} The selected rows of the data frame.\n * @throws {QvdValidationError} If any index is not an integer or is out of bounds.\n */\n rows(...args) {\n for (const index of args) {\n if (typeof index !== 'number' || !Number.isInteger(index)) {\n throw new QvdValidationError('rows() requires integer indices', {\n provided: index,\n type: typeof index,\n });\n }\n if (index < 0 || index >= this._data.length) {\n throw new QvdValidationError(`Row index ${index} out of bounds`, {\n index,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n }\n return new QvdDataFrame(\n args.map((index) => this._data[index]),\n this._columns,\n this._metadata,\n null,\n this._storedSymbols,\n );\n }\n\n /**\n * Returns the value at the specified row and column.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {any} The value at the specified row and column.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n at(row, column) {\n const index = this._cellIndex(row, column);\n\n return this._data[row][index];\n }\n\n /**\n * Returns the text of the value at the specified row and column.\n *\n * The text Qlik displays for it: a string cell is its own text, and a dual cell's text is its\n * `.text`. A number cell's text comes from the frame's `storedSymbols` - the dual it was read from,\n * or the string it was spelled as - and is null for a number that was stored as a pure number.\n *\n * ```js\n * const df = await QvdDataFrame.fromQvd('stockholm_temp.qvd');\n * df.at(0, 'date'); // -52593\n * df.textAt(0, 'date'); // '1756-01-01'\n * ```\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {string|null} The text, or null for NULL and for a number with no text.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n textAt(row, column) {\n const index = this._cellIndex(row, column);\n const value = this._data[row][index];\n\n if (typeof value === 'string') {\n return value;\n }\n\n if (typeof value === 'number') {\n const entry = storedSymbolsEntry(this._storedSymbols, column);\n\n return entry === null ? null : storedTextOf(entry, value);\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.text === 'string' ? dual.text : null;\n }\n\n /**\n * Checks a row and a column name, and returns the column's position.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {number} The column's position.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n * @private\n */\n _cellIndex(row, column) {\n if (typeof row !== 'number' || !Number.isInteger(row)) {\n throw new QvdValidationError('Row index must be an integer', {\n provided: row,\n type: typeof row,\n });\n }\n if (row < 0 || row >= this._data.length) {\n throw new QvdValidationError(`Row index ${row} out of bounds`, {\n index: row,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n return this._columns.indexOf(column);\n }\n\n /**\n * Selects the specified columns from the data frame.\n *\n * @param {...string} args The names of the columns to select.\n * @return {QvdDataFrame} The selected columns of the data frame.\n * @throws {QvdValidationError} If any column name does not exist.\n */\n select(...args) {\n for (const column of args) {\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n }\n const indices = args.map((arg) => this._columns.indexOf(arg));\n const data = this._data.map((row) => indices.map((index) => row[index]));\n const columns = indices.map((index) => this._columns[index]);\n // The constructor narrows the record to the fields kept, sharing their entries rather than copying them.\n return new QvdDataFrame(data, columns, this._metadata, null, this._storedSymbols);\n }\n\n /**\n * Returns the data frame as a dictionary.\n *\n * Everything a frame needs to write the same file again, as plain data: the header, and the\n * stored-symbol record that says what cells showing one half of a symbol were read from. So\n * `fromDict(await df.toDict())` writes what `df` writes, and so does a dictionary that went through\n * `JSON`, `structuredClone` or a worker on the way. The arrays are the frame's own, not copies.\n *\n * @return {Promise<QvdDataFrameDict>} The data frame as a dictionary.\n */\n async toDict() {\n return this.toJSON();\n }\n\n /**\n * The same dictionary `toDict` returns, synchronously, so `JSON.stringify(df)` gives something\n * `fromDict(JSON.parse(...))` can revive.\n *\n * @return {QvdDataFrameDict} The data frame as a dictionary.\n */\n toJSON() {\n return {\n columns: this._columns,\n data: this._data,\n metadata: this._metadata,\n storedSymbols: this._storedSymbols,\n };\n }\n\n /**\n * Persists the data frame to a QVD file.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional writing options.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function that receives progress updates during write operations.\n * @param {boolean} [options.atomic=true] Whether to replace the file rather than rewrite it. The QVD\n * is built beside it under a temporary name and renamed over it, so a write that fails leaves the\n * previous file exactly as it was, and a reader of the path - a Qlik reload, say - sees the old\n * file or the new one and never a part of either. False rewrites the file where it stands, as\n * every version before 2.0.0 did: that keeps its identity, including hard links, its owner and\n * permissions set on the file itself, and needs neither room for two copies nor permission to\n * create files in the directory. It also destroys the previous file as the write begins. A file\n * that does not exist yet is renamed into place either way, since there is nothing to rewrite.\n * @param {boolean} [options.fsync=true] Whether to wait for the contents to reach the disk before\n * resolving. It is what carries an atomic write's promise through a power loss - the contents are\n * on the disk before anything is renamed, so a crash leaves the previous file or the new one and\n * never a damaged one - and what reports a failing disk's deferred error instead of losing it. The\n * rename itself is not flushed, so a crash just after the call can still lose the replacement, or\n * a file that did not exist before. False resolves once the operating system has accepted the\n * bytes, which is faster and is what every version before 2.0.0 did.\n */\n async toQvd(path, options = {}) {\n const {QvdFileWriter} = await import('./QvdFileWriter.js');\n const writerOptions = {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n atomic: options.atomic,\n fsync: options.fsync,\n };\n await new QvdFileWriter(path, this, writerOptions).save();\n }\n\n /**\n * Loads a QVD file and returns its data frame.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional loading options.\n * @param {number|null} [options.maxRows] The maximum number of rows to load. Must be a non-negative\n * integer; if not specified or null, all rows are loaded. Anything else throws a QvdValidationError.\n * This is the older name for `limit`; the two are the same option and passing both throws.\n * @param {number|null} [options.limit] Rows to read, counting from `offset`. The same number as\n * `maxRows`, spelled so that it reads correctly beside an offset.\n * @param {number} [options.offset=0] File row to start at. An offset past the end of the file\n * returns no rows rather than throwing, so a paging loop terminates on its own.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear in the result. Unselected fields have their symbols skipped entirely rather than\n * parsed and discarded. An unknown or repeated name throws.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol - a number with the\n * text Qlik displays for it, such as a date, a timestamp or a formatted amount - reads as.\n * `'number'` gives its number, the value Qlik sums, sorts and compares by, so a date is its serial.\n * `'text'` gives its text. `'both'` gives a frozen `QvdDual` with `.number` and `.text`, whose\n * implicit conversions throw. Under `'number'` and `'text'` the other half is kept in\n * `storedSymbols`, so `toQvd` writes the dual back, and `textAt` returns any cell's text. An int, a\n * double, a string and NULL read the same in every mode: a number, a string and null. Anything else\n * throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite. A string symbol then\n * reads as `Number(text)`, so `'007'` is 7, in every `duals` mode; a dual read with\n * `duals: 'text'` reads as the number it stores. Blank text, and text such as `'8E5597'` whose\n * `Number()` is Infinity, stay strings. The text is kept in `storedSymbols`, so `toQvd` writes the\n * original string or dual back, and a value that two stored values read as is refused there\n * rather than written as either. Anything but a boolean throws.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}` as the\n * read proceeds - the same shape `toQvd`'s callback receives.\n * @param {AbortSignal} [options.signal] Cancels the read. The rejection is `signal.reason`,\n * which is a `DOMException` named `AbortError` unless you aborted with a reason of your own.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction (0.0-1.0) of the memory budget a load\n * may use. The budget is the smaller of the V8 heap limit and any container memory limit. Default\n * is 0.8; the estimate it scales accounts for the rows and columns being materialised, so this is\n * headroom for garbage collection rather than compensation for an inaccurate figure.\n * **Zero disables the memory check entirely.**\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes, above which\n * a lazy load switches to the two-pass filtering path. Defaults to 50MB.\n * @throws {QvdValidationError} If a window option is not a non-negative integer, if both\n * `maxRows` and `limit` are given, if `fields` names a column the file does not have, if `duals`\n * is not one of its modes, or if `coerceNumericStrings` is not a boolean.\n * @return {Promise<QvdDataFrame>} The data frame of the QVD file.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n return await new QvdFileReader(path, readerOptionsFrom(options)).load(windowFrom(options));\n }\n\n /**\n * Reads a QVD file in chunks, as an async generator of data frames.\n *\n * The file is opened once and its symbol table parsed once. Each chunk's records are read from the\n * file when that chunk is built, so what this holds is the symbol table and two chunks of rows,\n * whatever the size of the file: a 20 GB QVD iterates in the memory its symbol table needs. That\n * table is still parsed in full whatever the chunk size, because a stored index in the last chunk\n * can address the first symbol. On a high-cardinality file that table is the bulk of the cost, and\n * `readMetadata` is the only read that avoids it.\n *\n * The file stays open until the iteration ends. Running it to the end closes it, and so do\n * `break` or a throw inside `for await` and a call to `return()` on the iterator; an iterator\n * abandoned part-way without any of those holds the file until it is garbage-collected.\n *\n * ```js\n * for await (const chunk of QvdDataFrame.iterate('big.qvd', {chunkSize: 50_000})) {\n * process(chunk.data);\n * }\n * ```\n *\n * A window covering no rows yields nothing, so a loop over an exhausted offset simply does not\n * run its body.\n *\n * Every chunk carries the same `storedSymbols`, because the symbol table is parsed once for all of\n * them, so a chunk written on its own writes the symbols its cells were read from.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Reading options, with the meanings they have on `fromQvd`.\n * @param {number} [options.chunkSize=100000] Rows per frame. Must be a positive integer.\n * @param {number|null} [options.maxRows] Rows to cover. The older name for `limit`.\n * @param {number|null} [options.limit] Rows to cover, counting from `offset`.\n * @param {number} [options.offset=0] File row to start at.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should appear.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol reads as: its number,\n * its text, or a frozen `QvdDual` holding both. Anything else throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite - a string symbol as\n * `Number(text)`, a dual read as text as its stored number - with the text kept in every chunk's\n * `storedSymbols`. Anything but a boolean throws.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}`; progress\n * over the rows counts the whole window, not each chunk.\n * @param {AbortSignal} [options.signal] Cancels the iteration, rejecting with `signal.reason`.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction of the memory budget the read may use,\n * charged for two chunks of rows rather than the window. Zero disables the check.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size above which a\n * windowed read switches to two-pass filtering.\n * @return {AsyncGenerator<QvdDataFrame>} The chunks, in file order.\n */\n static async *iterate(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n const reader = new QvdFileReader(path, readerOptionsFrom(options));\n\n yield* reader.iterateRows(windowFrom(options), options.chunkSize === undefined ? 100000 : options.chunkSize);\n }\n\n /**\n * Reads a QVD file's schema and header metadata, without reading its data.\n *\n * Costs the same whatever the file's size, because it stops at the XML header - a few\n * kilobytes - and never touches the symbol or index tables.\n *\n * This is what `{maxRows: 0}` looks like but is not. That still reads and parses the whole\n * symbol table, which is 0.4MB on a 38MB taxi fixture but hundreds of megabytes on a\n * high-cardinality file. Use this when you want to know what is in a file rather than to\n * read any of it.\n *\n * No data frame comes back, deliberately: one with `data: []` would be indistinguishable\n * from an empty file at the call site.\n *\n * ```js\n * const {columns, rowCount, fields} = await QvdDataFrame.readMetadata('sales.qvd');\n * ```\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional reading options.\n * @param {string} [options.allowedDir] Optional allowed directory path, applied exactly as it\n * is for `fromQvd`.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}`, as on\n * the reads that return data. Only the `read` and `header` stages occur here; there are no\n * symbols to parse and no rows to build.\n * @param {AbortSignal} [options.signal] Cancels the read, rejecting with `signal.reason`.\n * @return {Promise<QvdFileMetadata>} The file's schema and header metadata.\n */\n static async readMetadata(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n return await new QvdFileReader(path, metadataOptionsFrom(options)).loadMetadata();\n }\n\n /**\n * Answers what a read would cost, and whether it fits, without doing it.\n *\n * Takes the options `fromQvd()` takes, plus `as` and `chunkSize` to say which read is being asked\n * about. Reads the header and the file's size and nothing else, at a cost that does not grow with\n * the file.\n *\n * The answer comes from the same function a read consults before it allocates anything, from the\n * same numbers, so **a read this approves is not refused later for memory** - and every suggestion\n * it carries has been read back through the check, so following one gives a read that fits.\n *\n * It answers about resources, so it answers only for a header it can trust. A header whose numbers\n * are not usable, or that claims more than the file holds, is refused as a `QvdCorruptedError` rather\n * than answered: sizing a read from numbers the file contradicts produced a memory verdict about a\n * file whose real problem was structural, and it was wrong in both directions - approving a read the\n * library then refused, and refusing another with advice that was refused too.\n *\n * That covers everything a reader can tell from the header: a field area past the end of the symbol\n * table, two fields claiming one area, a `Bias` that is neither 0 nor -2, a `BitWidth` past 31. Damage\n * that is not in the header - a value or an index the file has spoiled - is still found only by\n * reading, and still refused as a `QvdCorruptedError` after this has said the read fits.\n *\n * ```js\n * const answer = await QvdDataFrame.checkRead('huge.qvd', {as: 'columns', fields: ['Amount']});\n *\n * if (!answer.fits) {\n * console.log(answer.reason); // 'memory'\n * console.log(answer.suggestions); // [{option: 'limit', value: 1250000}, ...]\n * }\n * ```\n *\n * @param {string} path The QVD file.\n * @param {object} [options] What `fromQvd()` takes, plus the two below.\n * @param {'rows'|'columns'} [options.as='rows'] Which read is being asked about: `rows` builds row\n * arrays and `columns` does not, which is most of what a read costs.\n * @param {number|null} [options.chunkSize=null] The chunk an `iterate()` would use, which holds two\n * chunks of rows rather than the whole window.\n * @return {Promise<any>} The answer: `fits`, `reason` when it does not, `estimate`, `budget`,\n * `exact` and `suggestions`.\n * @throws {QvdValidationError} If an option's value is not valid, with `context.reason` of `option`.\n * @throws {QvdCorruptedError} If the header cannot be read, its numbers are not usable, or it claims\n * more than the file holds. The read refuses such a file too, though it may name the fault\n * differently - it gets there by planning the index table, where this gets there from the size.\n */\n static async checkRead(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const {as = 'rows', chunkSize = null} = options;\n\n if (as !== 'rows' && as !== 'columns') {\n throw new QvdValidationError(\"as must be 'rows' or 'columns'\", {\n provided: as,\n reason: 'option',\n option: 'as',\n value: as,\n file: path,\n });\n }\n\n if (chunkSize !== null) {\n requireChunkSize(chunkSize, path);\n }\n\n const reader = new QvdFileReader(path, {...readerOptionsFrom(options), materialisesRows: as === 'rows'});\n\n return await reader.checkRead(windowFrom(options), {chunkSize});\n }\n\n /**\n * Opens a QVD file for paging, reading its header and nothing else.\n *\n * Every other entry point is one read from start to finish. A viewer showing a hundred rows at a time\n * pays the header again on every page, and `iterate()` goes forwards only - it cannot jump to row five\n * million and it cannot go back. This holds the header so that `check()` costs nothing and a page can\n * be asked for by position.\n *\n * ```js\n * const qvd = await QvdDataFrame.open('sales.qvd', {allowedDir: '/data'});\n *\n * qvd.metadata; // read once, when it opened\n * const answer = qvd.check({offset: 0, limit: 100}); // no I/O at all\n * const page = await qvd.rows({offset: 5_000_000, limit: 100});\n * const cols = await qvd.columns({offset: 0, limit: 100, fields: ['Amount']});\n *\n * await qvd.close();\n * ```\n *\n * The header is read once, and so is each column: a column decoded for one page is kept for the pages\n * after it, so the first page costs about what a single read costs and the ones after it are cheap.\n * What a file has decoded is charged to the memory check, so a page is refused rather than the process\n * aborting, and `close()` releases it - close a file you have finished with.\n *\n * Each page still opens the file, and a first touch still decodes a whole column rather than only as\n * far as the page needs.\n *\n * @param {string} path The QVD file.\n * @param {object} [options] What `fromQvd()` takes - `allowedDir`, `fields`, `duals`,\n * `coerceNumericStrings`, `memorySafetyFactor` - describing the file and how its values read. A\n * window means nothing here: pages carry their own.\n * @return {Promise<import('./QvdFile.js').QvdFile>} The open file.\n * @throws {QvdValidationError} If an option's value is not valid, with `context.reason` of `option`.\n * @throws {QvdCorruptedError} If the header cannot be read, or describes a file this is not.\n */\n static async open(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const {QvdFile} = await import('./QvdFile.js');\n\n // One reader, holding the parsed header for the life of the file: it answers `check()` and nothing\n // else, so the state a page would clear is never its state. Pages get readers of their own.\n const reader = new QvdFileReader(path, readerOptionsFrom(options));\n\n // Paging, though it will never read a row: every page of this file is made by a paging reader, so\n // the estimates this one answers `check()` with have to be paging estimates. Without it a check\n // made before the first page priced a window's sample of the symbols, and the page that followed\n // held every one of them - the check and the read disagreeing about the same page.\n reader.beginPaging();\n\n // One header read, not two: the checks a page will rely on, then the schema built from the same\n // parse. Reading it once for the metadata and again for the checks would have opened the file twice\n // to answer one question.\n await reader.parseHeaderOnly();\n\n return new QvdFile(reader, reader.describeParsed(), {...options, path});\n }\n\n /**\n * Constructs a data frame from a dictionary.\n *\n * Takes what `toDict` returns. `metadata` and `storedSymbols` are optional; with the record, a frame\n * rebuilt from a read writes the symbols the read found - duals with their texts, strings with their\n * spelling - even after a trip through `JSON`. The record is checked, so a malformed one is refused\n * here rather than written.\n *\n * @param {QvdDataFrameDict} data The dictionary to construct the data frame from.\n * @return {Promise<QvdDataFrame>} The constructed data frame.\n * @throws {QvdValidationError} If `columns` or `data` is missing, `metadata` is not a plain object,\n * or `storedSymbols` is malformed or names a field that is not one of the columns.\n */\n static async fromDict(data) {\n if (!data.columns) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any columns.', {\n data,\n });\n }\n if (!data.data) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any data.', {\n data,\n });\n }\n\n const {metadata = null, storedSymbols = null} = data;\n\n if (metadata !== null && !isPlainObject(metadata)) {\n throw new QvdValidationError(`metadata must be a plain object; got ${describeType(metadata)}`, {\n type: typeof metadata,\n });\n }\n\n const record = normaliseStoredSymbols(storedSymbols);\n\n if (record !== null) {\n const unknown = record.find((entry) => !data.columns.includes(entry.field));\n\n if (unknown !== undefined) {\n throw new QvdValidationError(`storedSymbols names field '${unknown.field}', which is not one of the columns`, {\n field: unknown.field,\n availableColumns: data.columns,\n });\n }\n }\n\n return new QvdDataFrame(data.data, data.columns, metadata, null, record);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {INT32_MAX, INT32_MIN, asDual, checkNumber, checkText, describeType, isStoredAsInt} from './util/cellRules.js';\nimport {symbolByteLength, writeSymbol} from './util/symbolBytes.js';\n\n/**\n * Throws unless a value can be stored as the integer of a symbol.\n *\n * @param {any} value The value.\n * @param {Object} context Merged into the error's context.\n * @throws {QvdValidationError} If the value is not an integer inside the int32 range.\n */\nfunction checkInteger(value, context) {\n if (typeof value === 'number' && isStoredAsInt(value)) {\n return;\n }\n\n throw new QvdValidationError(\n `The integer of a symbol must be an integer from ${INT32_MIN} to ${INT32_MAX}; got ` +\n (typeof value === 'number' ? String(value) : describeType(value)),\n {...context, half: 'integer', type: typeof value},\n );\n}\n\n/**\n * One stored symbol, as the symbol table holds it: an int, a double, a string, or a dual of an int or\n * a double with its text.\n *\n * A low-level record of the file's contents rather than a cell. A read never puts one in a data frame\n * - a cell is a number, a string, a `QvdDual` or null - and the writer refuses one as a cell, pointing\n * at `QvdDual`, because a symbol carries a storage kind the writer derives from the value itself.\n *\n * The factories validate what they are given and throw `QvdValidationError` naming the half, so a\n * symbol built through them can be encoded. The constructor checks nothing, and\n * `toByteRepresentation` refuses whatever it cannot encode.\n */\nexport class QvdSymbol {\n /**\n * Constructs a new QVD symbol.\n *\n * @param {number|null} intValue The integer value.\n * @param {number|null} doubleValue The double value.\n * @param {string|null} stringValue The string value.\n */\n constructor(intValue, doubleValue, stringValue) {\n this._intValue = intValue;\n\n this._doubleValue = doubleValue;\n\n this._stringValue = stringValue;\n }\n\n /**\n * Returns the integer value of this symbol.\n *\n * @return {number|null} The integer value.\n */\n get intValue() {\n return this._intValue;\n }\n\n /**\n * Returns the double value of this symbol.\n *\n * @return {number|null} The double value.\n */\n get doubleValue() {\n return this._doubleValue;\n }\n\n /**\n * Returns the string value of this symbol.\n *\n * @return {string|null} The string value.\n */\n get stringValue() {\n return this._stringValue;\n }\n\n /**\n * Retrieves the primary value of this symbol. The primary value is descriptive raw value.\n * It is either the string value, the integer value or the double value, prioritized in this order.\n *\n * @return {number|string|null} The primary value.\n */\n toPrimaryValue() {\n if (null != this._stringValue) {\n return this._stringValue;\n } else if (null != this._intValue) {\n return this._intValue;\n } else if (null != this._doubleValue) {\n return this._doubleValue;\n } else {\n return null;\n }\n }\n\n /**\n * Converts the symbol to its byte representation.\n *\n * The kind is the one the symbol carries - an int, a double, a string, or a dual of an int or a\n * double with its text - so a symbol built with `fromDoubleValue(4)` stays a double. Each half is\n * checked before a byte is written, because `QvdSymbol`'s constructor checks nothing: an integer\n * outside int32 used to surface as a bare `RangeError` from `writeInt32LE`, a symbol holding an\n * integer and a double silently lost the double, a text with a NUL produced a symbol that ends\n * early, and a text with an unpaired surrogate was written with U+FFFD in its place.\n *\n * A half left `undefined` - `new QvdSymbol()`, or `new QvdSymbol(7)` - is absent, as it is to\n * `toPrimaryValue`. It used to be read as present: `new QvdSymbol(7)` threw a bare `TypeError` from\n * `Buffer.from`, and `new QvdSymbol(undefined, 4.5, '4.50')` was written as a dual of the integer 0.\n *\n * @return {Buffer} The byte representation of the symbol.\n * @throws {QvdValidationError} If the symbol holds both an integer and a double, holds nothing, or\n * holds a half no symbol can store. The message names the half.\n */\n toByteRepresentation() {\n const intValue = this._intValue ?? null;\n const doubleValue = this._doubleValue ?? null;\n const stringValue = this._stringValue ?? null;\n\n if (intValue !== null && doubleValue !== null) {\n throw new QvdValidationError('A symbol holds an integer or a double, not both', {\n intValue,\n doubleValue,\n });\n }\n\n if (intValue === null && doubleValue === null && stringValue === null) {\n throw new QvdValidationError('The symbol does not contain any value.', {\n intValue,\n doubleValue,\n stringValue,\n });\n }\n\n if (intValue !== null) {\n checkInteger(intValue, {});\n }\n\n if (doubleValue !== null) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n }\n\n if (stringValue !== null) {\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n }\n\n const number = intValue ?? doubleValue;\n const kind = number === null ? 4 : (intValue !== null ? 1 : 2) + (stringValue !== null ? 4 : 0);\n const buffer = Buffer.allocUnsafe(symbolByteLength(kind, number, stringValue));\n\n writeSymbol(buffer, 0, kind, number, stringValue);\n\n return buffer;\n }\n\n /**\n * Checks if this symbol is equal to another symbol.\n *\n * By shape rather than by class: another value is equal when its `intValue`, `doubleValue` and\n * `stringValue` are, compared with `===`, whichever copy of this library built it - `instanceof`\n * answers false for a symbol from the CommonJS build tested by the ESM one. A dual value, a `QvdDual`\n * or `{number, text}`, is equal to a dual symbol with the same number and text: a dual carries no\n * storage kind, so either kind matches.\n *\n * @param {*} value The object to compare with.\n * @return {boolean} True if the objects are equal, false otherwise.\n */\n equals(value) {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n const intValue = this._intValue ?? null;\n const doubleValue = this._doubleValue ?? null;\n const stringValue = this._stringValue ?? null;\n const dual = asDual(value);\n\n if (dual !== null) {\n return (\n stringValue !== null &&\n stringValue === dual.text &&\n (intValue === null) !== (doubleValue === null) &&\n (intValue ?? doubleValue) === dual.number\n );\n }\n\n if (!('intValue' in value && 'doubleValue' in value && 'stringValue' in value)) {\n return false;\n }\n\n return (\n intValue === (value.intValue ?? null) &&\n doubleValue === (value.doubleValue ?? null) &&\n stringValue === (value.stringValue ?? null)\n );\n }\n\n /**\n * Constructs a pure integer value symbol.\n *\n * @param {number} intValue The integer value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the integer is not an integer inside the int32 range.\n */\n static fromIntValue(intValue) {\n checkInteger(intValue, {});\n\n return new QvdSymbol(intValue, null, null);\n }\n\n /**\n * Constructs a pure double value symbol.\n *\n * @param {number} doubleValue The double value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the double is not a finite number.\n */\n static fromDoubleValue(doubleValue) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n\n return new QvdSymbol(null, doubleValue, null);\n }\n\n /**\n * Constructs a pure string value symbol.\n *\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the string is not a string, or holds a NUL or an unpaired surrogate.\n */\n static fromStringValue(stringValue) {\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\n return new QvdSymbol(null, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from an integer and a string value.\n *\n * @param {number} intValue The integer value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the integer is not an integer inside the int32 range, or the text\n * is not a string, or holds a NUL or an unpaired surrogate.\n */\n static fromDualIntValue(intValue, stringValue) {\n checkInteger(intValue, {});\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\n return new QvdSymbol(intValue, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from a double and a string value.\n *\n * @param {number} doubleValue The double value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the double is not a finite number, or the text is not a string,\n * or holds a NUL or an unpaired surrogate.\n */\n static fromDualDoubleValue(doubleValue, stringValue) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\n return new QvdSymbol(null, doubleValue, stringValue);\n }\n}\n","// @ts-check\n\nexport {QvdSymbol} from './QvdSymbol.js';\nexport {QvdDual} from './QvdDual.js';\nexport {qlikSerialToDate, dateToQlikSerial} from './util/qlikDate.js';\nexport {QvdDataFrame} from './QvdDataFrame.js';\nexport {QvdColumnTable, QvdColumn} from './QvdColumnTable.js';\nexport {QvdFile} from './QvdFile.js';\nexport {QvdFileReader} from './QvdFileReader.js';\nexport {QvdFileWriter} from './QvdFileWriter.js';\nexport {\n QvdError,\n QvdParseError,\n QvdValidationError,\n QvdIOError,\n QvdCorruptedError,\n QvdSecurityError,\n} from './QvdErrors.js';\n","// @ts-check\n\nimport {types} from 'util';\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {asDual, describeType} from './cellRules.js';\n\n/** Qlik's day 0: 30 December 1899, so that 1 January 1900 is day 2, as in Excel and Lotus 1-2-3. */\nconst QLIK_EPOCH_MS = Date.UTC(1899, 11, 30);\n\nconst MS_PER_DAY = 86400000;\n\n/** The furthest a JavaScript `Date` reaches either side of 1970, in milliseconds. */\nconst MAX_DATE_MS = 8.64e15;\n\n/** The serials of the first and last days a `Date` can hold: -99974431 and 100025569. */\nconst MIN_SERIAL = (-MAX_DATE_MS - QLIK_EPOCH_MS) / MS_PER_DAY;\nconst MAX_SERIAL = (MAX_DATE_MS - QLIK_EPOCH_MS) / MS_PER_DAY;\n\n/**\n * Converts a Qlik date or timestamp serial to a JavaScript `Date`.\n *\n * Qlik stores a date as the number of days since 30 December 1899, with the time of day as the\n * fraction: 42382.260416666664 is 13 January 2016 at 06:15. That number is what a date field's cell\n * reads as, whether Qlik stored it as a dual with the date's text or as a pure number with a `DATE`\n * format - and it is the `number` of a dual value read with `{duals: 'both'}`.\n *\n * **The serial has no time zone, and the result is read in UTC.** Qlik's serial means \"this wall-clock\n * date and time\", not an instant. The `Date` returned carries those wall-clock fields in its UTC\n * getters, so `toISOString()` and `getUTCHours()` show what Qlik shows. The local-time getters apply\n * the machine's own offset, which is almost never what you want here.\n *\n * Checked against the text Qlik stored beside every date in stockholm_temp and every trip start\n * timestamp in a chicago_taxi_rides file, and rounded to the millisecond, which is finer than any Qlik\n * timestamp text shows.\n *\n * ```js\n * qlikSerialToDate(-52593).toISOString(); // '1756-01-01T00:00:00.000Z'\n * qlikSerialToDate(new QvdDual(-52593, '1756-01-01')).toISOString(); // a dual works too, through its number\n * ```\n *\n * @param {number|import('../QvdDual.js').QvdDual|{number: number, text: string}} serial The serial, or a dual whose number is one.\n * @return {Date} The date, with Qlik's wall-clock fields in its UTC getters.\n * @throws {QvdValidationError} If the serial is not a finite number, or is a day a `Date` cannot hold.\n */\nexport function qlikSerialToDate(serial) {\n const dual = asDual(serial);\n const number = dual === null ? serial : dual.number;\n\n if (typeof number !== 'number' || !Number.isFinite(number)) {\n throw new QvdValidationError('A Qlik date serial must be a finite number', {\n provided: describeType(number),\n type: typeof serial,\n });\n }\n\n const ms = Math.round(QLIK_EPOCH_MS + number * MS_PER_DAY);\n\n // Past this a Date is Invalid Date, which fails later and somewhere else - in toISOString(), say.\n if (!(Math.abs(ms) <= MAX_DATE_MS)) {\n throw new QvdValidationError(`A Qlik date serial of ${number} is outside the range a JavaScript Date can hold`, {\n serial: number,\n minSerial: MIN_SERIAL,\n maxSerial: MAX_SERIAL,\n });\n }\n\n return new Date(ms);\n}\n\n/**\n * Converts a JavaScript `Date` to a Qlik date or timestamp serial.\n *\n * The inverse of `qlikSerialToDate`, and it reads the date's UTC fields for the same reason: a\n * serial is a wall-clock value. Build the `Date` from UTC parts - `new Date(Date.UTC(2016, 0, 13, 6,\n * 15))`, or an ISO string ending in `Z` - to get the serial Qlik would store for that date and time.\n *\n * For every date and timestamp checked against `qlikSerialToDate`, converting Qlik's serial to a\n * `Date` and back returns Qlik's stored double exactly.\n *\n * A `Date` from another realm - a `vm` context, or a Node core module under Jest - is accepted: the\n * check is on what the value is, not on which `Date` constructor made it.\n *\n * To write a date Qlik will treat as a date, pair the serial with the text to display:\n *\n * ```js\n * const when = new Date(Date.UTC(2016, 0, 13, 6, 15));\n * const cell = new QvdDual(dateToQlikSerial(when), '2016-01-13 06:15:00');\n * ```\n *\n * @param {Date} date The date.\n * @return {number} The serial: whole days since 30 December 1899, with the time of day as the fraction.\n * @throws {QvdValidationError} If the argument is not a valid `Date`.\n */\nexport function dateToQlikSerial(date) {\n const ms = types.isDate(date) ? Date.prototype.getTime.call(date) : Number.NaN;\n\n if (Number.isNaN(ms)) {\n throw new QvdValidationError('dateToQlikSerial needs a valid Date', {\n provided: describeType(date),\n type: typeof date,\n });\n }\n\n return (ms - QLIK_EPOCH_MS) / MS_PER_DAY;\n}\n"]}
1
+ {"version":3,"sources":["../src/QvdErrors.js","../src/util/cellRules.js","../src/util/symbolBytes.js","../src/QvdDual.js","../src/util/optionTypes.js","../src/util/readOptions.js","../src/util/storedSymbols.js","../src/util/linkTarget.js","../src/util/validatePath.js","../src/util/ioErrors.js","../src/util/openChecked.js","../src/util/replaceFile.js","../src/util/bitUtils.js","../src/util/seenNumbers.js","../src/QvdFileWriter.js","../src/util/memoryUtils.js","../src/util/validationUtils.js","../src/util/symbolParser.js","../src/util/resolveSymbols.js","../src/QvdColumnTable.js","../src/QvdFileReader.js","../src/QvdFile.js","../src/QvdDataFrame.js","../src/QvdSymbol.js","../src/index.js","../src/util/qlikDate.js"],"names":["fs","path","assert","crypto","wait","refuse","held","QvdFileReader","xml","QvdColumnTable","reader","QvdFileWriter","QvdFile"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,IAYM,WAAA,CAAA,CAMO,QAAA,CAAA,CAwBA,aAAA,CAAA,CAiBA,kBAAA,CAAA,CAoCA,YAiBA,iBAAA,CAAA,CAyBA;AAzIb,IAAA,cAAA,GAAA,KAAA,CAAA;AAAA,EAAA,kBAAA,GAAA;AAYA,IAAM,WAAA,uBAAkB,GAAA,EAAI;AAMrB,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAA,MAlBpC;AAkBoC,QAAA,MAAA,CAAA,IAAA,EAAA,UAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUlC,YAAY,OAAA,EAAS,IAAA,EAAM,UAAU,EAAC,EAAG,UAAU,MAAA,EAAW;AAC5D,QAAA,KAAA,CAAM,SAAS,OAAO,CAAA;AAEtB,QAAA,IAAA,CAAK,IAAA,GAAO,WAAA,CAAY,GAAA,CAAI,GAAA,CAAA,MAAU,KAAK,GAAA,CAAA,MAAA,CAAW,IAAA;AACtD,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,QAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,QAAA,KAAA,CAAM,iBAAA,CAAkB,IAAA,EAAM,IAAA,CAAK,WAAW,CAAA;AAAA,MAChD;AAAA,KACF;AAMO,IAAM,aAAA,GAAN,cAA4B,QAAA,CAAS;AAAA,MA1C5C;AA0C4C,QAAA,MAAA,CAAA,IAAA,EAAA,eAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQ1C,YAAY,OAAA,EAAS,OAAA,GAAU,EAAC,EAAG,UAAU,MAAA,EAAW;AACtD,QAAA,KAAA,CAAM,OAAA,EAAS,iBAAA,EAAmB,OAAA,EAAS,OAAO,CAAA;AAAA,MACpD;AAAA,KACF;AAMO,IAAM,kBAAA,GAAN,cAAiC,QAAA,CAAS;AAAA,MA3DjD;AA2DiD,QAAA,MAAA,CAAA,IAAA,EAAA,oBAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQ/C,YAAY,OAAA,EAAS,OAAA,GAAU,EAAC,EAAG,UAAU,MAAA,EAAW;AACtD,QAAA,KAAA,CAAM,OAAA,EAAS,sBAAA,EAAwB,OAAA,EAAS,OAAO,CAAA;AAAA,MACzD;AAAA,KACF;AAyBO,IAAM,UAAA,GAAN,cAAyB,QAAA,CAAS;AAAA,MA/FzC;AA+FyC,QAAA,MAAA,CAAA,IAAA,EAAA,YAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQvC,YAAY,OAAA,EAAS,OAAA,GAAU,EAAC,EAAG,UAAU,MAAA,EAAW;AACtD,QAAA,KAAA,CAAM,OAAA,EAAS,cAAA,EAAgB,OAAA,EAAS,OAAO,CAAA;AAAA,MACjD;AAAA,KACF;AAMO,IAAM,iBAAA,GAAN,cAAgC,QAAA,CAAS;AAAA,MAhHhD;AAgHgD,QAAA,MAAA,CAAA,IAAA,EAAA,mBAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQ9C,YAAY,OAAA,EAAS,OAAA,GAAU,EAAC,EAAG,UAAU,MAAA,EAAW;AACtD,QAAA,KAAA,CAAM,OAAA,EAAS,qBAAA,EAAuB,OAAA,EAAS,OAAO,CAAA;AAAA,MACxD;AAAA,KACF;AAcO,IAAM,gBAAA,GAAN,cAA+B,QAAA,CAAS;AAAA,MAzI/C;AAyI+C,QAAA,MAAA,CAAA,IAAA,EAAA,kBAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQ7C,YAAY,OAAA,EAAS,OAAA,GAAU,EAAC,EAAG,UAAU,MAAA,EAAW;AACtD,QAAA,KAAA,CAAM,OAAA,EAAS,oBAAA,EAAsB,OAAA,EAAS,OAAO,CAAA;AAAA,MACvD;AAAA,KACF;AAEA,IAAA,WAAA,CAAY,GAAA,CAAI,UAAU,UAAU,CAAA;AACpC,IAAA,WAAA,CAAY,GAAA,CAAI,eAAe,eAAe,CAAA;AAC9C,IAAA,WAAA,CAAY,GAAA,CAAI,oBAAoB,oBAAoB,CAAA;AACxD,IAAA,WAAA,CAAY,GAAA,CAAI,YAAY,YAAY,CAAA;AACxC,IAAA,WAAA,CAAY,GAAA,CAAI,mBAAmB,mBAAmB,CAAA;AACtD,IAAA,WAAA,CAAY,GAAA,CAAI,kBAAkB,kBAAkB,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACpG7C,SAAS,OAAO,KAAA,EAAO;AAC5B,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,EAAU;AAC/C,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,IAAI,KAAA,CAAM,UAAU,CAAA,KAAM,IAAA,EAAM;AAC9B,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AACzB,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAE9B,IAAA,OAAO,KAAK,MAAA,KAAW,CAAA,KACnB,KAAK,CAAC,CAAA,KAAM,YAAY,IAAA,CAAK,CAAC,MAAM,MAAA,IAAY,IAAA,CAAK,CAAC,CAAA,KAAM,MAAA,IAAU,KAAK,CAAC,CAAA,KAAM,YAClF,KAAA,GACA,IAAA;AAAA,EACN,CAAA,CAAA,MAAQ;AAGN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAcO,SAAS,cAAc,KAAA,EAAO;AACnC,EAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,YAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACvE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,cAAA,CAAe,KAAK,CAAA;AAE7C,EAAA,OAAO,SAAA,KAAc,IAAA,IAAQ,MAAA,CAAO,cAAA,CAAe,SAAS,CAAA,KAAM,IAAA;AACpE;AAeO,SAAS,cAAc,IAAA,EAAM;AAClC,EAAA,OAAO,IAAA,CAAK,MAAK,KAAM,EAAA,IAAM,OAAO,QAAA,CAAS,MAAA,CAAO,IAAI,CAAC,CAAA;AAC3D;AAiBO,SAAS,cAAc,KAAA,EAAO;AACnC,EAAA,OAAO,OAAO,SAAA,CAAU,KAAK,CAAA,IAAK,KAAA,IAAS,aAAa,KAAA,IAAS,SAAA;AACnE;AASO,SAAS,cAAc,KAAA,EAAO;AACnC,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,CAAA,GAAA,EAAM,YAAA,CAAa,KAAK,CAAC,CAAA,cAAA,CAAA;AAAA,EAClC;AAEA,EAAA,OAAO,MAAA,CAAO,SAAS,KAAK,CAAA,GAAI,OAAO,CAAA,GAAA,EAAM,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAC5D;AAoBO,SAAS,YAAY,KAAA,EAAO;AACjC,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,EAAC,QAAQ,MAAA,EAAM;AAAA,EACxB;AAIA,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA;AAElC,EAAA,IAAI,aAAa,EAAA,EAAI;AACnB,IAAA,OAAO,EAAC,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAQ;AAAA,EACjC;AAIA,EAAA,OAAO,KAAA,CAAM,YAAA,EAAa,GAAI,IAAA,GAAO,EAAC,QAAQ,WAAA,EAAa,QAAA,EAAU,sBAAA,CAAuB,KAAK,CAAA,EAAC;AACpG;AASA,SAAS,uBAAuB,KAAA,EAAO;AACrC,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,KAAA,CAAM,QAAQ,KAAA,EAAA,EAAS;AACjD,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,CAAW,KAAK,CAAA;AAEnC,IAAA,IAAI,IAAA,GAAO,KAAA,IAAU,IAAA,GAAO,KAAA,EAAQ;AAClC,MAAA;AAAA,IACF;AAIA,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,CAAW,KAAA,GAAQ,CAAC,CAAA;AAEvC,IAAA,IAAI,IAAA,IAAQ,KAAA,IAAU,IAAA,IAAQ,KAAA,IAAU,QAAQ,KAAA,EAAQ;AACtD,MAAA,KAAA,EAAA;AACA,MAAA;AAAA,IACF;AAEA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAA;AACT;AAgBO,SAAS,WAAA,CAAY,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS;AACnD,EAAA,IAAI,aAAA,CAAc,KAAK,CAAA,KAAM,IAAA,EAAM;AACjC,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,OAAA,KAAY,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,EAAU;AACjD,IAAA,MAAM,IAAI,mBAAmB,kDAAA,EAAoD;AAAA,MAC/E,GAAG,OAAA;AAAA,MACH,QAAA,EAAU,OAAO,KAAK;AAAA,KACvB,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,IAAI,mBAAmB,CAAA,EAAG,OAAA,IAAW,UAAU,CAAA,8BAAA,EAAiC,YAAA,CAAa,KAAK,CAAC,CAAA,CAAA,EAAI;AAAA,IAC3G,GAAG,OAAA;AAAA,IACH,MAAM,OAAO;AAAA,GACd,CAAA;AACH;AAYO,SAAS,SAAA,CAAU,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS;AACjD,EAAA,MAAM,OAAA,GAAU,YAAY,KAAK,CAAA;AAEjC,EAAA,IAAI,YAAY,IAAA,EAAM;AACpB,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,OAAA,CAAQ,WAAW,MAAA,EAAQ;AAC7B,IAAA,MAAM,IAAI,mBAAmB,CAAA,EAAG,OAAO,0BAA0B,YAAA,CAAa,KAAK,CAAC,CAAA,CAAA,EAAI;AAAA,MACtF,GAAG,OAAA;AAAA,MACH,MAAM,OAAO;AAAA,KACd,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,OAAA,CAAQ,WAAW,WAAA,EAAa;AAClC,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,EAAG,OAAO,CAAA,qCAAA,CAAA,EAAyC;AAAA,MAC9E,GAAG,OAAA;AAAA,MACH,UAAU,OAAA,CAAQ;AAAA,KACnB,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,EAAG,OAAO,CAAA,+BAAA,CAAA,EAAmC,EAAC,GAAG,OAAA,EAAS,QAAA,EAAU,OAAA,CAAQ,QAAA,EAAS,CAAA;AACpH;AAWO,SAAS,gBAAgB,KAAA,EAAO;AACrC,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,MAAM,WAAA,EAAa,IAAA;AAEhC,IAAA,OAAO,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,KAAK,IAAA,GAAO,IAAA;AAAA,EAC1D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAcO,SAAS,aAAa,KAAA,EAAO;AAClC,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAE7B,IAAA,OAAO,OAAO,QAAA,CAAS,KAAK,CAAA,GAAI,UAAA,GAAa,OAAO,KAAK,CAAA;AAAA,EAC3D;AAEA,EAAA,IAAI,OAAO,UAAU,WAAA,EAAa;AAChC,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,CAAA,EAAA,EAAK,OAAO,KAAK,CAAA,CAAA;AAAA,EAC1B;AAEA,EAAA,IAAI,IAAA;AAEJ,EAAA,IAAI;AACF,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,MAAA,OAAO,UAAA;AAAA,IACT;AAIA,IAAA,IAAA,GAAO,eAAA,CAAgB,KAAK,CAAA,IAAK,MAAA,CAAO,SAAA,CAAU,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAA,CAAE,CAAA;AAElF,IAAA,IAAI,SAAS,QAAA,EAAU;AAKrB,MAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AACzB,QAAA,OAAO,mDAAA;AAAA,MACT;AAEA,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAE9B,MAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,QAAA,OAAO,gBAAA;AAAA,MACT;AAGA,MAAA,OAAO,CAAA,yBAAA,EAA4B,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,EAAG,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,UAAU,EAAE,CAAA,CAAA;AAAA,IACjG;AAAA,EACF,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,WAAA;AAAA,EACT;AAGA,EAAA,OAAO,CAAA,EAAG,WAAW,IAAA,CAAK,IAAI,IAAI,IAAA,GAAO,GAAG,IAAI,IAAI,CAAA,CAAA;AACtD;AApXA,IAea,SAAA,EAGA,WAGA,GAAA,EAUA,UAAA;AA/Bb,IAAA,cAAA,GAAA,KAAA,CAAA;AAAA,EAAA,uBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AAaO,IAAM,SAAA,GAAY,WAAA;AAGlB,IAAM,SAAA,GAAY,UAAA;AAGlB,IAAM,GAAA,GAAM,MAAA,CAAO,YAAA,CAAa,CAAC,CAAA;AAUjC,IAAM,UAAA,mBAAa,MAAA,CAAO,GAAA,CAAI,eAAe,CAAA;AAwBpC,IAAA,MAAA,CAAA,MAAA,EAAA,QAAA,CAAA;AAuCA,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAuBA,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAmBA,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAWA,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AA0BA,IAAA,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAyBP,IAAA,MAAA,CAAA,sBAAA,EAAA,wBAAA,CAAA;AAqCO,IAAA,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AA4BA,IAAA,MAAA,CAAA,SAAA,EAAA,WAAA,CAAA;AAiCA,IAAA,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAsBA,IAAA,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;AChST,SAAS,MAAA,CAAO,QAAQ,IAAA,EAAM;AACnC,EAAA,IAAI,WAAW,IAAA,EAAM;AACnB,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,IAAI,aAAA,CAAc,MAAM,CAAA,EAAG;AACzB,IAAA,OAAO,IAAA,KAAS,OAAO,CAAA,GAAI,CAAA;AAAA,EAC7B;AAEA,EAAA,OAAO,IAAA,KAAS,OAAO,CAAA,GAAI,CAAA;AAC7B;AAUO,SAAS,gBAAA,CAAiB,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM;AACnD,EAAA,MAAM,WAAA,GAAc,IAAA,KAAS,CAAA,IAAK,IAAA,KAAS,CAAA,GAAI,IAAI,IAAA,KAAS,CAAA,IAAK,IAAA,KAAS,CAAA,GAAI,CAAA,GAAI,CAAA;AAElF,EAAA,MAAM,SAAA,GAAY,QAAQ,CAAA,GAAI,MAAA,CAAO,WAAW,IAAA,EAAM,MAAM,IAAI,CAAA,GAAI,CAAA;AAEpE,EAAA,OAAO,IAAI,WAAA,GAAc,SAAA;AAC3B;AAgBO,SAAS,WAAA,CAAY,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,QAAQ,IAAA,EAAM;AAC9D,EAAA,MAAA,CAAO,QAAQ,CAAA,GAAI,IAAA;AAEnB,EAAA,IAAI,IAAA,KAAS,CAAA,IAAK,IAAA,KAAS,CAAA,EAAG;AAE5B,IAAA,MAAA,GAAS,MAAA,CAAO,YAAA,CAAa,MAAA,EAAQ,MAAM,CAAA;AAAA,EAC7C,CAAA,MAAA,IAAW,IAAA,KAAS,CAAA,IAAK,IAAA,KAAS,CAAA,EAAG;AAEnC,IAAA,MAAA,GAAS,MAAA,CAAO,aAAA,CAAc,MAAA,EAAQ,MAAM,CAAA;AAAA,EAC9C;AAEA,EAAA,IAAI,QAAQ,CAAA,EAAG;AAEb,IAAA,MAAA,IAAU,MAAA,CAAO,KAAA,CAAM,IAAA,EAAM,MAAA,EAAQ,MAAM,CAAA;AAC3C,IAAA,MAAA,CAAO,QAAQ,CAAA,GAAI,CAAA;AAAA,EACrB;AAEA,EAAA,OAAO,MAAA;AACT;AA1FA,IAAA,gBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,yBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AA4BgB,IAAA,MAAA,CAAA,MAAA,EAAA,QAAA,CAAA;AAoBA,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAsBA,IAAA,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;AC4ChB,SAAS,YAAA,CAAa,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM;AAC1C,EAAA,MAAA,CAAO,iBAAiB,MAAA,EAAQ;AAAA,IAC9B,MAAA,EAAQ,EAAC,KAAA,EAAO,MAAA,EAAQ,YAAY,IAAA,EAAI;AAAA,IACxC,IAAA,EAAM,EAAC,KAAA,EAAO,IAAA,EAAM,YAAY,IAAA;AAAI,GACrC,CAAA;AAED,EAAA,MAAA,CAAO,OAAO,MAAM,CAAA;AACtB;AAcO,SAAS,cAAA,CAAe,QAAQ,IAAA,EAAM;AAC3C,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAA;AAE5C,EAAA,YAAA,CAAa,IAAA,EAAM,QAAQ,IAAI,CAAA;AAE/B,EAAA,OAAO,IAAA;AACT;AA/IA,IAgCa;AAhCb,IAAA,YAAA,GAAA,KAAA,CAAA;AAAA,EAAA,gBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AA8BO,IAAM,UAAN,MAAc;AAAA,MAhCrB;AAgCqB,QAAA,MAAA,CAAA,IAAA,EAAA,SAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWnB,WAAA,CAAY,QAAQ,IAAA,EAAM;AACxB,QAAA,WAAA,CAAY,MAAA,EAAQ,4BAAA,EAA8B,EAAC,IAAA,EAAM,UAAS,CAAA;AAClE,QAAA,SAAA,CAAU,IAAA,EAAM,0BAAA,EAA4B,EAAC,IAAA,EAAM,QAAO,CAAA;AAE1D,QAAA,YAAA,CAAa,IAAA,EAAM,QAAQ,IAAI,CAAA;AAAA,MACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,CAAC,MAAA,CAAO,WAAW,CAAA,GAAI;AACrB,QAAA,MAAM,IAAI,SAAA;AAAA,UACR,CAAA,4BAAA,EAA+B,KAAK,MAAM,CAAA,KAAA,EAAQ,KAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC,CAAA,sBAAA;AAAA,SAC7E;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,MAAA,GAAS;AACP,QAAA,OAAO,EAAC,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,IAAA,EAAM,KAAK,IAAA,EAAI;AAAA,MAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,iBAAC,MAAA,CAAO,GAAA,CAAI,4BAA4B,CAAC,CAAA,GAAI;AAC3C,QAAA,OAAO,CAAA,QAAA,EAAW,KAAK,MAAM,CAAA,EAAA,EAAK,KAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,MAC7D;AAAA;AAAA,MAGA,KAAK,MAAA,CAAO,WAAW,CAAA,GAAI;AACzB,QAAA,OAAO,SAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,OAAO,OAAO,KAAA,EAAO;AACnB,QAAA,OAAO,MAAA,CAAO,KAAK,CAAA,KAAM,IAAA;AAAA,MAC3B;AAAA,KACF;AAIA,IAAA,MAAA,CAAO,eAAe,OAAA,CAAQ,SAAA,EAAW,YAAY,EAAC,KAAA,EAAO,MAAK,CAAA;AAYzD,IAAA,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AAqBO,IAAA,MAAA,CAAA,cAAA,EAAA,gBAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;AC9GT,SAAS,cAAc,KAAA,EAAO,EAAC,MAAA,EAAQ,IAAA,EAAM,WAAS,EAAG;AAC9D,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM;AACzC,IAAA,OAAO,SAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,UAAU,SAAA,EAAW;AAC9B,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,EAAG,MAAM,CAAA,sBAAA,CAAA,EAA0B;AAAA,MAC9D,MAAA;AAAA,MACA,QAAA,EAAU,KAAA;AAAA,MACV,MAAM,OAAO,KAAA;AAAA,MACb;AAAA,KACD,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,KAAA;AACT;AA1CA,IAAA,gBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,yBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AAyBgB,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACAT,SAAS,eAAA,CAAgB,KAAA,EAAO,IAAA,EAAM,QAAA,EAAU;AACrD,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,CAAC,OAAO,SAAA,CAAU,KAAK,CAAA,IAAK,KAAA,GAAQ,CAAA,EAAG;AACtE,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,EAAG,IAAI,CAAA,+BAAA,CAAA,EAAmC;AAAA,MACrE,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,IAAA;AAAA,MACR,KAAA;AAAA,MACA,QAAA,EAAU,KAAA;AAAA,MACV,MAAM,OAAO,KAAA;AAAA,MACb,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,KAAA;AACT;AAoBO,SAAS,eAAA,CAAgB,QAAQ,QAAA,EAAU;AAChD,EAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,KAAW,MAAA,EAAW;AAC3C,IAAA,OAAO,EAAC,MAAA,EAAQ,CAAA,EAAG,KAAA,EAAO,IAAA,EAAI;AAAA,EAChC;AAIA,EAAA,IAAI,OAAO,WAAW,QAAA,EAAU;AAC9B,IAAA,OAAO,EAAC,QAAQ,CAAA,EAAG,KAAA,EAAO,gBAAgB,MAAA,EAAQ,SAAA,EAAW,QAAQ,CAAA,EAAC;AAAA,EACxE;AAEA,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AACvD,IAAA,MAAM,IAAI,mBAAmB,qEAAA,EAAuE;AAAA,MAClG,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,OAAA;AAAA,MACR,KAAA,EAAO,MAAA;AAAA,MACP,QAAA,EAAU,MAAA;AAAA,MACV,MAAM,OAAO,MAAA;AAAA,MACb,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,EAAC,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAO,GAAI,MAAA;AACjC,EAAA,MAAM,UAAA,GAAa,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA;AACpD,EAAA,MAAM,YAAA,GAAe,OAAA,KAAY,MAAA,IAAa,OAAA,KAAY,IAAA;AAE1D,EAAA,IAAI,cAAc,YAAA,EAAc;AAC9B,IAAA,MAAM,IAAI,mBAAmB,iFAAA,EAAmF;AAAA,MAC9G,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,OAAA;AAAA,MACR,KAAA,EAAO,KAAA;AAAA,MACP,OAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,WAAW,MAAA,IAAa,MAAA,KAAW,OAAO,CAAA,GAAI,eAAA,CAAgB,MAAA,EAAQ,QAAA,EAAU,QAAQ,CAAA;AAAA,IAChG,KAAA,EAAO,UAAA,GACH,eAAA,CAAgB,KAAA,EAAO,OAAA,EAAS,QAAQ,CAAA,GACxC,YAAA,GACE,eAAA,CAAgB,OAAA,EAAS,SAAA,EAAW,QAAQ,CAAA,GAC5C;AAAA,GACR;AACF;AAcO,SAAS,gBAAA,CAAiB,WAAW,QAAA,EAAU;AACpD,EAAA,IAAI,OAAO,cAAc,QAAA,IAAY,CAAC,OAAO,SAAA,CAAU,SAAS,CAAA,IAAK,SAAA,IAAa,CAAA,EAAG;AACnF,IAAA,MAAM,IAAI,mBAAmB,sCAAA,EAAwC;AAAA,MACnE,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,WAAA;AAAA,MACR,KAAA,EAAO,SAAA;AAAA,MACP,QAAA,EAAU,SAAA;AAAA,MACV,MAAM,OAAO,SAAA;AAAA,MACb,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,SAAA;AACT;AAqBO,SAAS,aAAA,CAAc,QAAQ,SAAA,EAAW;AAC/C,EAAA,MAAM,OAAO,MAAA,CAAO,aAAA,CAAc,SAAS,CAAA,IAAK,SAAA,GAAY,IAAI,SAAA,GAAY,CAAA;AAC5E,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,QAAQ,IAAI,CAAA;AAE3C,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,MAAA,CAAO,KAAA,KAAU,IAAA,GAAO,QAAA,GAAW,MAAA,CAAO,KAAA,EAAO,IAAA,GAAO,MAAM,CAAC;AAAA,GAC7F;AACF;AAqBO,SAAS,YAAA,CAAa,MAAA,EAAQ,SAAA,EAAW,QAAA,EAAU;AACxD,EAAA,IAAI,SAAA,KAAc,IAAA,IAAQ,SAAA,KAAc,MAAA,EAAW;AACjD,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,SAAS,CAAA,EAAG;AAC7B,IAAA,MAAM,IAAI,mBAAmB,wCAAA,EAA0C;AAAA,MACrE,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,QAAA;AAAA,MACR,KAAA,EAAO,SAAA;AAAA,MACP,QAAA,EAAU,SAAA;AAAA,MACV,MAAM,OAAO,SAAA;AAAA,MACb,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,YAAY,MAAA,CAAO,GAAA,CAAI,CAAoB,KAAA,KAAU,KAAA,CAAM,WAAW,CAAC,CAAA;AAI7E,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,IAAA,MAAM,IAAI,mBAAmB,qCAAA,EAAuC;AAAA,MAClE,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,QAAA;AAAA,MACR,KAAA,EAAO,SAAA;AAAA,MACP,gBAAA,EAAkB,SAAA;AAAA,MAClB,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAI;AAErB,EAAA,OAAO,SAAA,CAAU,GAAA,CAAI,CAAC,IAAA,KAAS;AAC7B,IAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,MAAA,MAAM,IAAI,mBAAmB,6BAAA,EAA+B;AAAA,QAC1D,MAAA,EAAQ,QAAA;AAAA,QACR,MAAA,EAAQ,QAAA;AAAA,QACR,KAAA,EAAO,IAAA;AAAA,QACP,QAAA,EAAU,IAAA;AAAA,QACV,MAAM,OAAO,IAAA;AAAA,QACb,gBAAA,EAAkB,SAAA;AAAA,QAClB,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,EAAG;AAClB,MAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,OAAA,EAAU,IAAI,CAAA,iBAAA,CAAA,EAAqB;AAAA,QAC9D,MAAA,EAAQ,QAAA;AAAA,QACR,MAAA,EAAQ,QAAA;AAAA,QACR,KAAA,EAAO,IAAA;AAAA,QACP,MAAA,EAAQ,IAAA;AAAA,QACR,MAAA,EAAQ,SAAA;AAAA,QACR,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAEA,IAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAEb,IAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,OAAA,CAAQ,IAAI,CAAA;AAEpC,IAAA,IAAI,UAAU,EAAA,EAAI;AAChB,MAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,QAAA,EAAW,IAAI,CAAA,gBAAA,CAAA,EAAoB;AAAA,QAC9D,MAAA,EAAQ,QAAA;AAAA,QACR,MAAA,EAAQ,QAAA;AAAA,QACR,KAAA,EAAO,IAAA;AAAA,QACP,MAAA,EAAQ,IAAA;AAAA,QACR,gBAAA,EAAkB,SAAA;AAAA,QAClB,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB,CAAC,CAAA;AACH;AAqBO,SAAS,cAAA,CAAe,OAAO,QAAA,EAAU;AAC9C,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM;AACzC,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,UAAA,CAAW,QAAA,CAAS,KAAK,CAAA,EAAG;AAC/B,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,qBAAA,EAAwB,UAAA,CAAW,IAAI,CAAC,IAAA,KAAS,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,EAAI;AAAA,MACvG,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,OAAA;AAAA,MACR,KAAA;AAAA,MACA,QAAA,EAAU,KAAA;AAAA,MACV,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,KAAA;AACT;AAuBO,SAAS,6BAAA,CAA8B,OAAO,QAAA,EAAU;AAC7D,EAAA,OAAO,aAAA,CAAc,OAAO,EAAC,MAAA,EAAQ,wBAAwB,IAAA,EAAM,QAAA,EAAU,SAAA,EAAW,KAAA,EAAM,CAAA;AAChG;AAYO,SAAS,kBAAkB,OAAA,EAAS;AACzC,EAAA,OAAO;AAAA,IACL,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,oBAAoB,OAAA,CAAQ,kBAAA;AAAA,IAC5B,0BAA0B,OAAA,CAAQ,wBAAA;AAAA,IAClC,MAAA,EAAQ,OAAA,CAAQ,MAAA,KAAW,MAAA,GAAY,OAAO,OAAA,CAAQ,MAAA;AAAA,IACtD,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,sBAAsB,OAAA,CAAQ,oBAAA;AAAA,IAC9B,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,QAAQ,OAAA,CAAQ;AAAA,GAClB;AACF;AAoBO,SAAS,oBAAoB,OAAA,EAAS;AAC3C,EAAA,OAAO;AAAA,IACL,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,QAAQ,OAAA,CAAQ;AAAA,GAClB;AACF;AASO,SAAS,WAAW,OAAA,EAAS;AAClC,EAAA,OAAO,EAAC,QAAQ,OAAA,CAAQ,MAAA,EAAQ,OAAO,OAAA,CAAQ,KAAA,EAAO,OAAA,EAAS,OAAA,CAAQ,OAAA,EAAO;AAChF;AA1XA,IAmQM,UAAA;AAnQN,IAAA,gBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,yBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AAwBgB,IAAA,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAiCA,IAAA,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AA2DA,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAkCA,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AA6BA,IAAA,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AA6EhB,IAAM,aAAa,MAAA,CAAO,MAAA,CAAO,CAAC,QAAA,EAAU,MAAA,EAAQ,MAAM,CAAC,CAAA;AAkB3C,IAAA,MAAA,CAAA,cAAA,EAAA,gBAAA,CAAA;AAuCA,IAAA,MAAA,CAAA,6BAAA,EAAA,+BAAA,CAAA;AAcA,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AA+BA,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AAeA,IAAA,MAAA,CAAA,UAAA,EAAA,YAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACpTT,SAAS,mBAAmB,OAAA,EAAS;AAC1C,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AAEpC,EAAA,OAAA,CAAQ,IAAI,MAAM,CAAA;AAElB,EAAA,OAAO,MAAA;AACT;AAQO,SAAS,mBAAA,CAAoB,UAAU,MAAA,EAAQ;AACpD,EAAA,IAAI,QAAA,KAAa,QAAQ,OAAO,QAAA,KAAa,YAAY,MAAA,CAAO,YAAA,CAAa,QAAQ,CAAA,EAAG;AACtF,IAAA,MAAA,CAAO,cAAA,CAAe,QAAA,EAAU,cAAA,EAAgB,EAAC,KAAA,EAAO,QAAQ,UAAA,EAAY,KAAA,EAAO,YAAA,EAAc,IAAA,EAAK,CAAA;AAAA,EACxG;AACF;AAUA,SAAS,MAAA,CAAO,SAAS,OAAA,EAAS;AAChC,EAAA,MAAM,IAAI,kBAAA,CAAmB,OAAA,EAAS,OAAO,CAAA;AAC/C;AAeO,SAAS,uBAAuB,MAAA,EAAQ;AAC7C,EAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,KAAW,MAAA,EAAW;AAC3C,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,EAAG;AACrD,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC1B,IAAA,MAAA,CAAO,CAAA,qDAAA,EAAwD,YAAA,CAAa,MAAM,CAAC,CAAA,CAAA,EAAI;AAAA,MACrF,MAAA,EAAQ,eAAA;AAAA,MACR,MAAM,OAAO;AAAA,KACd,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAI;AAEvB,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,GAAA,CAAI,CAAC,OAAO,KAAA,KAAU;AAC3C,IAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,OAAO,KAAA,CAAM,KAAA,KAAU,QAAA,EAAU;AAC1G,MAAA,MAAA,CAAO,qEAAA,EAAuE,EAAC,KAAA,EAAO,KAAA,EAAM,CAAA;AAAA,IAC9F;AAEA,IAAA,MAAM,EAAC,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,OAAK,GAAI,KAAA;AAExC,IAAA,IAAI,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,EAAG;AACrB,MAAA,MAAA,CAAO,8BAA8B,KAAK,CAAA,OAAA,CAAA,EAAW,EAAC,KAAA,EAAO,KAAA,EAAO,OAAM,CAAA;AAAA,IAC5E;AAEA,IAAA,MAAA,CAAO,IAAI,KAAK,CAAA;AAEhB,IAAA,IACE,CAAC,MAAM,OAAA,CAAQ,MAAM,KACrB,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,IACtB,CAAC,MAAM,OAAA,CAAQ,KAAK,KACpB,MAAA,CAAO,MAAA,KAAW,QAAQ,MAAA,IAC1B,MAAA,CAAO,MAAA,KAAW,KAAA,CAAM,MAAA,EACxB;AACA,MAAA,MAAA,CAAO,CAAA,8DAAA,EAAiE,KAAK,CAAA,8BAAA,CAAA,EAAkC;AAAA,QAC7G,KAAA;AAAA,QACA,KAAA,EAAO;AAAA,OACR,CAAA;AAAA,IACH;AAEA,IAAA,KAAA,IAAS,MAAA,GAAS,CAAA,EAAG,MAAA,GAAS,MAAA,CAAO,QAAQ,MAAA,EAAA,EAAU;AACrD,MAAA,MAAM,KAAA,GAAQ,OAAO,MAAM,CAAA;AAC3B,MAAA,MAAM,MAAA,GAAS,QAAQ,MAAM,CAAA;AAC7B,MAAA,MAAM,IAAA,GAAO,MAAM,MAAM,CAAA;AACzB,MAAA,MAAM,OAAA,GAAU,EAAC,KAAA,EAAO,MAAA,EAAM;AAE9B,MAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,UAAU,QAAA,EAAU;AAC1D,QAAA,MAAA,CAAO,CAAA,0DAAA,EAA6D,YAAA,CAAa,KAAK,CAAC,CAAA,CAAA,EAAI;AAAA,UACzF,GAAG,OAAA;AAAA,UACH,MAAM,OAAO;AAAA,SACd,CAAA;AAAA,MACH;AAEA,MAAA,IAAI,WAAW,IAAA,EAAM;AACnB,QAAA,WAAA,CAAY,MAAA,EAAQ,4BAA4B,OAAO,CAAA;AAAA,MACzD;AAEA,MAAA,IAAI,SAAS,IAAA,EAAM;AACjB,QAAA,SAAA,CAAU,IAAA,EAAM,0BAA0B,OAAO,CAAA;AAAA,MACnD;AAKA,MAAA,MAAM,UAAA,GACJ,MAAA,KAAW,IAAA,IAAQ,IAAA,KAAS,IAAA,GACxB,aAAA,CAAc,KAAA,EAAO,MAAM,CAAA,IAAK,KAAA,KAAU,IAAA,GAC1C,MAAA,KAAW,IAAA,IAAQ,IAAA,KAAS,IAAA,GAC1B,KAAA,KAAU,IAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,GACrE,MAAA,KAAW,IAAA,IAAQ,aAAA,CAAc,KAAA,EAAO,MAAM,CAAA;AAEtD,MAAA,IAAI,CAAC,UAAA,EAAY;AACf,QAAA,MAAA;AAAA,UACE,MAAA,KAAW,IAAA,IAAQ,IAAA,KAAS,IAAA,GACxB,0CAAA,GACA,wDAAA;AAAA,UACJ,EAAC,GAAG,OAAA,EAAS,KAAA,EAAO,QAAQ,IAAA;AAAI,SAClC;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,OAAO,MAAA,CAAO;AAAA,MACnB,KAAA;AAAA,MACA,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AAAA,MACpC,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA;AAAA,MACtC,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,KAAA,CAAM,OAAO;AAAA,KACnC,CAAA;AAAA,EACH,CAAC,CAAA;AAED,EAAA,OAAO,mBAAmB,OAAO,CAAA;AACnC;AAWO,SAAS,mBAAA,CAAoB,QAAQ,OAAA,EAAS;AACnD,EAAA,IAAI,WAAW,IAAA,EAAM;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,OAAO,MAAA,CAAO,CAAC,UAAU,OAAA,CAAQ,QAAA,CAAS,KAAA,CAAM,KAAK,CAAC,CAAA;AAEnE,EAAA,OAAO,KAAK,MAAA,KAAW,MAAA,CAAO,MAAA,GAAS,MAAA,GAAS,mBAAmB,IAAI,CAAA;AACzE;AASO,SAAS,kBAAA,CAAmB,QAAQ,KAAA,EAAO;AAChD,EAAA,IAAI,WAAW,IAAA,EAAM;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,OAAO,IAAA,CAAK,CAAC,UAAU,KAAA,CAAM,KAAA,KAAU,KAAK,CAAA,IAAK,IAAA;AAC1D;AAuBO,SAAS,iBAAiB,KAAA,EAAO;AAEtC,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAI;AAExB,EAAA,KAAA,IAAS,QAAQ,KAAA,CAAM,MAAA,CAAO,SAAS,CAAA,EAAG,KAAA,IAAS,GAAG,KAAA,EAAA,EAAS;AAC7D,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,CAAM,KAAK,CAAA;AAE9B,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,MAAA,CAAO,KAAK,GAAG,IAAI,CAAA;AAAA,IACvC;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AASO,SAAS,YAAA,CAAa,OAAO,KAAA,EAAO;AACzC,EAAA,IAAI,OAAA,GAAU,UAAA,CAAW,GAAA,CAAI,KAAK,CAAA;AAElC,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,OAAA,GAAU,iBAAiB,KAAK,CAAA;AAChC,IAAA,UAAA,CAAW,GAAA,CAAI,OAAO,OAAO,CAAA;AAAA,EAC/B;AAEA,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,IAAK,IAAA;AAC/B;AASO,SAAS,aAAA,CAAc,GAAG,CAAA,EAAG;AAClC,EAAA,OAAO,CAAA,KAAM,CAAA,IAAM,CAAA,KAAM,CAAA,IAAK,CAAA,KAAM,CAAA;AACtC;AAnTA,IAgDa,gBAQP,OAAA,EAkMA,UAAA;AA1PN,IAAA,kBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,2BAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AACA,IAAA,cAAA,EAAA;AA6CO,IAAM,cAAA,mBAAiB,MAAA,CAAO,GAAA,CAAI,qBAAqB,CAAA;AAQ9D,IAAM,OAAA,uBAAc,OAAA,EAAQ;AAYZ,IAAA,MAAA,CAAA,kBAAA,EAAA,oBAAA,CAAA;AAcA,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AAcP,IAAA,MAAA,CAAA,MAAA,EAAA,QAAA,CAAA;AAiBO,IAAA,MAAA,CAAA,sBAAA,EAAA,wBAAA,CAAA;AA0GA,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AAiBA,IAAA,MAAA,CAAA,kBAAA,EAAA,oBAAA,CAAA;AAchB,IAAM,UAAA,uBAAiB,OAAA,EAAQ;AAef,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAsBA,IAAA,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AAkBA,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;AC9PT,SAAS,iBAAiB,MAAA,EAAQ;AAEvC,EAAA,IAAI,IAAA;AAEJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAOA,GAAA,CAAG,UAAU,MAAM,CAAA;AAAA,EAC5B,CAAA,CAAA,MAAQ;AAGN,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,IAAA,CAAK,cAAA,EAAe,EAAG;AAI1B,IAAA,OAAO,UAAA;AAAA,EACT;AAGA,EAAA,IAAI,WAAA;AAEJ,EAAA,IAAI;AACF,IAAA,WAAA,GAAcA,GAAA,CAAG,aAAa,MAAM,CAAA;AAAA,EACtC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,eAAA;AAAA,EACT;AAEA,EAAA,IAAIC,KAAA,CAAK,UAAA,CAAW,WAAW,CAAA,EAAG;AAChC,IAAA,OAAO,WAAA;AAAA,EACT;AAaA,EAAA,IAAI;AACF,IAAA,OAAOA,KAAA,CAAK,QAAQD,GAAA,CAAG,YAAA,CAAaC,MAAK,OAAA,CAAQ,MAAM,CAAC,CAAA,EAAG,WAAW,CAAA;AAAA,EACxE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,eAAA;AAAA,EACT;AACF;AAnGA,IAea,eAMA,UAAA,EAOA,eAAA;AA5Bb,IAAA,eAAA,GAAA,KAAA,CAAA;AAAA,EAAA,wBAAA,GAAA;AAeO,IAAM,aAAA,GAAgB,EAAA;AAMtB,IAAM,UAAA,0BAAoB,YAAY,CAAA;AAOtC,IAAM,eAAA,0BAAyB,iBAAiB,CAAA;AAuBvC,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;AC3BhB,SAAS,0BAAA,CAA2B,iBAAiB,YAAA,EAAc;AAMjE,EAAA,MAAM,mBAAA,GAAsB,QAAQ,QAAA,KAAa,OAAA;AACjD,EAAA,MAAM,IAAA,GAAO,mBAAA,GAAsB,eAAA,CAAgB,WAAA,EAAY,GAAI,eAAA;AACnE,EAAA,MAAM,MAAA,GAAS,mBAAA,GAAsB,YAAA,CAAa,WAAA,EAAY,GAAI,YAAA;AAElE,EAAA,MAAM,QAAA,GAAWA,KAAAA,CAAK,QAAA,CAAS,IAAA,EAAM,MAAM,CAAA;AAI3C,EAAA,IAAI,aAAa,EAAA,EAAI;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAIA,KAAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,QAAA,KAAa,QAAQ,CAAC,QAAA,CAAS,WAAW,CAAA,EAAA,EAAKA,KAAAA,CAAK,GAAG,CAAA,CAAE,CAAA;AAClE;AA6CA,SAAS,uBAAuB,MAAA,EAAQ;AACtC,EAAA,IAAI,OAAA,GAAU,MAAA;AACd,EAAA,IAAI,MAAA,GAAS,MAAA;AACb,EAAA,IAAI,QAAA,GAAW,KAAA;AAEf,EAAA,IAAI,qBAAA,GAAwB,KAAA;AAC5B,EAAA,IAAI,IAAA,GAAO,CAAA;AAEX,EAAA,WAAS;AACP,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAUD,GAAAA,CAAG,YAAA,CAAa,OAAO,CAAA;AAQvC,MAAA,MAAM,eAAA,GACJ,QAAA,IAAY,CAAC,qBAAA,GAAwBC,KAAAA,CAAK,IAAA,CAAK,OAAA,EAASA,KAAAA,CAAK,QAAA,CAAS,OAAA,EAAS,MAAM,CAAC,CAAA,GAAI,MAAA;AAE5F,MAAA,OAAO,EAAC,OAAA,EAAS,MAAA,EAAQ,CAAC,QAAA,EAAU,QAAQ,eAAA,EAAe;AAAA,IAC7D,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAA;AAAA;AAAA,QAAuC,KAAA,EAAQ;AAAA,OAAA;AAMrD,MAAA,IAAI,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,SAAA,EAAW;AAC3C,QAAA,OAAO,IAAA;AAAA,MACT;AAIA,MAAA,MAAM,QAAA,GAAW,iBAAiB,OAAO,CAAA;AAEzC,MAAA,IAAI,aAAa,eAAA,EAAiB;AAChC,QAAA,OAAO,OAAA;AAAA,MACT;AAEA,MAAA,IAAI,aAAa,UAAA,EAAY;AAC3B,QAAA,IAAI,EAAE,OAAO,aAAA,EAAe;AAC1B,UAAA,OAAO,OAAA;AAAA,QACT;AAEA,QAAA,OAAA,GAAU,QAAA;AAKV,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,qBAAA,GAAwB,IAAA;AAAA,QAC1B,CAAA,MAAO;AACL,UAAA,MAAA,GAAS,QAAA;AAAA,QACX;AAEA,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,GAASA,KAAAA,CAAK,OAAA,CAAQ,OAAO,CAAA;AACnC,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,OAAO,IAAA;AAAA,MACT;AACA,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,OAAA,GAAU,MAAA;AAAA,IACZ;AAAA,EACF;AACF;AA0CA,SAAS,uBAAA,CAAwB,iBAAiB,YAAA,EAAc;AAE9D,EAAA,IAAI,QAAA;AAEJ,EAAA,IAAI;AAGF,IAAA,QAAA,GAAWD,GAAAA,CAAG,SAASA,GAAAA,CAAG,YAAA,CAAa,eAAe,CAAA,EAAG,EAAC,MAAA,EAAQ,IAAA,EAAK,CAAA;AAAA,EACzE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ,uBAAuB,YAAY,CAAA;AAKjD,EAAA,IAAI,UAAU,OAAA,EAAS;AACrB,IAAA,OAAO,EAAC,SAAA,EAAW,KAAA,EAAO,MAAA,EAAQ,YAAA,EAAc,OAAO,IAAA,EAAI;AAAA,EAC7D;AAEA,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,OAAO,IAAA;AAAA,EACT;AAKA,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,MAAA,GAAS,KAAA,CAAM,UAAU,KAAA,CAAM,MAAA;AAEpD,EAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,EAAA,IAAI,UAAU,KAAA,CAAM,OAAA;AAIpB,EAAA,KAAA,IAAS,KAAA,GAAQ,IAAA,IAAQ,KAAA,GAAQ,KAAA,EAAO;AACtC,IAAA,MAAM,WAAA,GAAc,SAAS,KAAA,CAAM,MAAA;AACnC,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI;AAQF,MAAA,IAAA,GAAO,WAAA,GAAcA,GAAAA,CAAG,SAAA,CAAU,OAAA,EAAS,EAAC,MAAA,EAAQ,IAAA,EAAK,CAAA,GAAIA,IAAG,QAAA,CAAS,OAAA,EAAS,EAAC,MAAA,EAAQ,MAAK,CAAA;AAAA,IAClG,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAIA,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,KAAA,GAAQ,IAAA;AAAA,IACV;AAGA,IAAA,IAAI,KAAK,GAAA,KAAQ,QAAA,CAAS,OAAO,IAAA,CAAK,GAAA,KAAQ,SAAS,GAAA,EAAK;AAC1D,MAAA,OAAO,EAAC,SAAA,EAAW,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAK;AAAA,IACxC;AAEA,IAAA,MAAM,MAAA,GAASC,KAAAA,CAAK,OAAA,CAAQ,OAAO,CAAA;AACnC,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,OAAO,EAAC,SAAA,EAAW,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAK;AAAA,IACzC;AACA,IAAA,OAAA,GAAU,MAAA;AAAA,EACZ;AACF;AA8CO,SAAS,SAAA,CAAU,UAAU,UAAA,EAAY;AAG9C,EAAA,IAAI,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,CAAS,WAAW,CAAA,EAAG;AACzD,IAAA,MAAM,IAAI,mBAAmB,qCAAA,EAAuC;AAAA,MAClE,QAAA,EAAU,QAAA;AAAA,MACV,MAAM,OAAO;AAAA,KACd,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,eAAe,MAAA,IAAa,UAAA,KAAe,IAAA,IAAQ,OAAO,eAAe,QAAA,EAAU;AACrF,IAAA,MAAM,IAAI,mBAAmB,gDAAA,EAAkD;AAAA,MAC7E,QAAA,EAAU,UAAA;AAAA,MACV,MAAM,OAAO;AAAA,KACd,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,QAAA,CAAS,QAAA,CAAS,IAAI,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,iBAAiB,4CAAA,EAA8C;AAAA,MACvE,IAAA,EAAM,QAAA;AAAA,MACN,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,YAAA,GAAeA,KAAAA,CAAK,OAAA,CAAQ,QAAQ,CAAA;AAU1C,EAAA,MAAM,OAAA,GAAU,UAAA,IAAc,OAAA,CAAQ,GAAA,EAAI;AAC1C,EAAA,MAAM,eAAA,GAAkBA,KAAAA,CAAK,OAAA,CAAQ,OAAO,CAAA;AAE5C,EAAA,MAAM,MAAA,GAAS,uBAAA,CAAwB,eAAA,EAAiB,YAAY,CAAA;AACpE,EAAA,MAAM,YAAY,MAAA,KAAW,IAAA,GAAO,2BAA2B,eAAA,EAAiB,YAAY,IAAI,MAAA,CAAO,SAAA;AAEvG,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,MAAM,IAAI,iBAAiB,wCAAA,EAA0C;AAAA,MACnE,IAAA,EAAM,QAAA;AAAA,MACN,YAAA;AAAA,MACA,UAAA,EAAY,eAAA;AAAA,MACZ,MAAA,EAAQ,2BAAA;AAAA;AAAA;AAAA,MAGR,KAAA,EAAO,MAAA,KAAW,IAAA,GAAO,SAAA,GAAY;AAAA,KACtC,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,WAAW,IAAA,EAAM;AACnB,IAAA,OAAO,EAAC,IAAA,EAAM,YAAA,EAAc,IAAA,EAAM,eAAA,EAAiB,QAAQ,YAAA,EAAc,KAAA,EAAO,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAK;AAAA,EACrG;AAEA,EAAA,OAAO,EAAC,IAAA,EAAM,YAAA,EAAc,IAAA,EAAM,eAAA,EAAiB,MAAA,EAAQ,MAAA,CAAO,MAAA,EAAQ,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,MAAA,EAAQ,IAAA,EAAI;AAC7G;AApXA,IAwDM,OAAA;AAxDN,IAAA,iBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,0BAAA,GAAA;AAIA,IAAA,cAAA,EAAA;AACA,IAAA,eAAA,EAAA;AAmBS,IAAA,MAAA,CAAA,0BAAA,EAAA,4BAAA,CAAA;AAgCT,IAAM,OAAA,0BAAiB,SAAS,CAAA;AAkCvB,IAAA,MAAA,CAAA,sBAAA,EAAA,wBAAA,CAAA;AA8GA,IAAA,MAAA,CAAA,uBAAA,EAAA,yBAAA,CAAA;AAkHO,IAAA,MAAA,CAAA,SAAA,EAAA,WAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACvShB,SAAS,cAAc,KAAA,EAAO;AAC5B,EAAA,MAAM,SAAA;AAAA;AAAA,IAAqE;AAAA,GAAA;AAE3E,EAAA,OACE,SAAA,KAAc,IAAA,IACd,OAAO,SAAA,KAAc,QAAA,IACrB,OAAO,SAAA,CAAU,OAAA,KAAY,QAAA,IAC7B,OAAO,SAAA,CAAU,IAAA,KAAS,QAAA;AAE9B;AAmBO,SAAS,SAAA,CAAU,KAAA,EAAO,IAAA,EAAM,SAAA,EAAW;AAChD,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AACzB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,EAAC,OAAA,EAAS,OAAA,EAAS,IAAA,EAAI;AAAA;AAAA,IAAqE;AAAA,GAAA;AAElG,EAAA,OAAO,IAAI,UAAA;AAAA,IACT,CAAA,UAAA,EAAa,SAAS,CAAA,eAAA,EAAkB,OAAO,CAAA,CAAA;AAAA,IAC/C,EAAC,IAAA,EAAM,SAAA,EAAW,OAAA,EAAS,IAAA,EAAI;AAAA,IAC/B,EAAC,OAAO,KAAA;AAAK,GACf;AACF;AAcO,SAAS,gBAAA,CAAiB,MAAM,SAAA,EAAW;AAChD,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,MAAM,SAAA,CAAU,KAAA,EAAO,IAAA,EAAM,SAAS,CAAA;AAAA,EACxC,CAAA;AACF;AAuBA,eAAsB,UAAA,CAAW,MAAA,EAAQ,MAAA,EAAQ,GAAA,EAAK;AACpD,EAAA,IAAI,MAAA;AAEJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,MAAM,GAAA,EAAI;AAAA,EACrB,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,MAAA,CAAO,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AACnC,IAAA,MAAM,KAAA;AAAA,EACR;AAEA,EAAA,MAAM,MAAA,CAAO,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM,CAAA;AAEjC,EAAA,OAAO,MAAA;AACT;AAjHA,IAAA,aAAA,GAAA,KAAA,CAAA;AAAA,EAAA,sBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AAiBS,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AA4BO,IAAA,MAAA,CAAA,SAAA,EAAA,WAAA,CAAA;AA0BA,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AA2BM,IAAA,MAAA,CAAA,UAAA,EAAA,YAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;ACnDtB,SAAS,iBAAA,CAAkB,SAAS,MAAA,EAAQ;AAC1C,EAAA,OAAO,IAAI,gBAAA,CAAiB,CAAA,yBAAA,EAA4B,YAAA,CAAa,MAAM,CAAC,CAAA,CAAA,EAAI;AAAA,IAC9E,MAAM,OAAA,CAAQ,IAAA;AAAA,IACd,cAAc,OAAA,CAAQ,MAAA;AAAA,IACtB,YAAY,OAAA,CAAQ,IAAA;AAAA,IACpB,MAAA,EAAQ,qBAAA;AAAA,IACR;AAAA,GACD,CAAA;AACH;AA+CA,eAAsB,WAAA,CAAY,SAAS,OAAA,EAAS,MAAA,EAAQ,EAAC,QAAA,GAAW,QAAA,EAAQ,GAAI,EAAC,EAAG;AACtF,EAAAC,OAAA,CAAO,OAAA,KAAY,MAAA,IAAU,OAAA,CAAQ,KAAA,KAAU,MAAM,8CAA8C,CAAA;AAEnG,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,MAAA,GAAS,QAAA,GAAW,CAAA;AAC7C,EAAA,MAAM,KAAA,GAAA,CAAS,OAAA,KAAY,SAAA,GAAY,QAAA,GAAW,QAAA,IAAY,QAAA;AAG9D,EAAA,IAAI,MAAA;AAEJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,MAAMF,GAAAA,CAAG,QAAA,CAAS,IAAA,CAAK,OAAA,CAAQ,QAAQ,KAAK,CAAA;AAAA,EACvD,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,EAAC,IAAA,EAAI;AAAA;AAAA,MAAoC,SAAU;AAAC,KAAA;AAE1D,IAAA,IAAI,OAAA,CAAQ,UAAU,QAAA,KAAa,CAAA,IAAK,SAAS,MAAA,IAAa,aAAA,CAAc,GAAA,CAAI,IAAI,CAAA,EAAG;AACrF,MAAA,MAAM,iBAAA,CAAkB,SAAS,kBAAkB,CAAA;AAAA,IACrD;AAEA,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AAEA,EAAA,MAAM,QAAQ,OAAA,CAAQ,KAAA;AAEtB,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,MAAA,MAAM,MAAA,CAAO,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM;AAAA,MAAC,CAAC,CAAA;AACnC,MAAA,MAAM,iBAAA,CAAkB,SAAS,UAAU,CAAA;AAAA,IAC7C;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAK,EAAC,QAAQ,IAAA,EAAK,CAAA,CAAE,KAAA,CAAM,MAAM,CAAA;AAE7D,IAAA,IAAI,OAAO,GAAA,KAAQ,KAAA,CAAM,OAAO,MAAA,CAAO,GAAA,KAAQ,MAAM,GAAA,EAAK;AACxD,MAAA,MAAM,iBAAA,CAAkB,SAAS,UAAU,CAAA;AAAA,IAC7C;AAGA,IAAA,IAAI,OAAA,KAAY,SAAA,IAAa,KAAA,CAAM,MAAA,EAAO,EAAG;AAC3C,MAAA,MAAM,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,CAAE,MAAM,MAAM,CAAA;AAAA,IACvC;AAAA,EACF,SAAS,KAAA,EAAO;AAEd,IAAA,MAAM,MAAA,CAAO,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM;AAAA,IAAC,CAAC,CAAA;AACnC,IAAA,MAAM,KAAA;AAAA,EACR;AAEA,EAAA,OAAO,MAAA;AACT;AA1JA,IAea,QAAA,EAEN,QAAA,EAAU,QAAA,EAMX,aAAA,EASA,YAAA;AAhCN,IAAA,gBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,yBAAA,GAAA;AAMA,IAAA,cAAA,EAAA;AASO,IAAM,QAAA,GAAWA,GAAAA,CAAG,SAAA,CAAU,UAAA,IAAc,CAAA;AAEnD,IAAA,CAAM,EAAC,QAAA,EAAU,QAAA,EAAA,GAAYA,GAAAA,CAAG,SAAA;AAMhC,IAAM,gCAAgB,IAAI,GAAA,CAAI,CAAC,OAAA,EAAS,QAAQ,CAAC,CAAA;AASjD,IAAM,YAAA,GAAe;AAAA,MACnB,gBAAA,EAAkB,sDAAA;AAAA,MAClB,QAAA,EAAU,+DAAA;AAAA,MACV,QAAA,EAAU;AAAA,KACZ;AAaS,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAuDa,IAAA,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;AC/EtB,SAAS,YAAA,CAAa,MAAM,MAAA,EAAQ;AAClC,EAAA,IAAI,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA,IAAK,MAAA,EAAQ;AACrC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,IAAA,GAAO,EAAA;AACX,EAAA,IAAI,KAAA,GAAQ,CAAA;AAEZ,EAAA,KAAA,MAAW,aAAa,IAAA,EAAM;AAC5B,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,UAAA,CAAW,SAAS,CAAA;AAExC,IAAA,IAAI,KAAA,GAAQ,OAAO,MAAA,EAAQ;AACzB,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,IAAQ,SAAA;AACR,IAAA,KAAA,IAAS,IAAA;AAAA,EACX;AAEA,EAAA,OAAO,IAAA;AACT;AAyBO,SAAS,iBAAiB,MAAA,EAAQ;AACvC,EAAA,MAAM,KAAA,GAAQ,UAAUG,OAAA,CAAO,WAAA,CAAY,CAAC,CAAA,CAAE,QAAA,CAAS,KAAK,CAAC,CAAA,IAAA,CAAA;AAC7D,EAAA,MAAM,IAAA,GAAO,CAAA,EAAG,YAAA,CAAaF,KAAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG,cAAA,GAAiB,KAAA,CAAM,MAAM,CAAC,CAAA,EAAG,KAAK,CAAA,CAAA;AAE1F,EAAA,OAAOA,MAAK,IAAA,CAAKA,KAAAA,CAAK,OAAA,CAAQ,MAAM,GAAG,IAAI,CAAA;AAC7C;AAgCA,eAAe,QAAA,CAAS,IAAA,EAAM,EAAC,QAAA,GAAW,OAAA,CAAQ,UAAU,MAAA,GAAS,YAAA,EAAY,GAAI,EAAC,EAAG;AACvF,EAAA,KAAA,IAAS,OAAA,GAAU,KAAK,OAAA,EAAA,EAAW;AACjC,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,EAAK;AAAA,IACpB,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,EAAC,IAAA,EAAI;AAAA;AAAA,QAAoC,SAAU;AAAC,OAAA;AAE1D,MAAA,IAAI,QAAA,KAAa,OAAA,IAAW,OAAA,IAAW,MAAA,CAAO,MAAA,IAAU,IAAA,KAAS,MAAA,IAAa,CAAC,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA,EAAG;AAC/F,QAAA,MAAM,KAAA;AAAA,MACR;AAEA,MAAA,MAAMG,UAAA,CAAK,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA,IAC5B;AAAA,EACF;AACF;AAcO,SAAS,UAAA,CAAW,IAAA,EAAM,EAAA,EAAI,OAAA,EAAS;AAC5C,EAAA,OAAO,QAAA,CAAS,MAAMJ,GAAAA,CAAG,QAAA,CAAS,OAAO,IAAA,EAAM,EAAE,GAAG,OAAO,CAAA;AAC7D;AAeA,eAAsB,eAAA,CAAgB,MAAM,OAAA,EAAS;AACnD,EAAA,IAAI;AASF,IAAA,MAAM,QAAA,CAAS,MAAMA,GAAAA,CAAG,QAAA,CAAS,EAAA,CAAG,IAAA,EAAM,EAAC,KAAA,EAAO,IAAA,EAAK,CAAA,EAAG,OAAO,CAAA;AAEjE,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAxKA,IAYM,gBAqEA,MAAA,EAOA,YAAA;AAxFN,IAAA,gBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,yBAAA,GAAA;AAYA,IAAM,cAAA,GAAiB,GAAA;AAad,IAAA,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AA6CO,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAWhB,IAAM,yBAAS,IAAI,GAAA,CAAI,CAAC,OAAA,EAAS,QAAA,EAAU,OAAO,CAAC,CAAA;AAOnD,IAAM,eAAe,CAAC,EAAA,EAAI,IAAI,EAAA,EAAI,EAAA,EAAI,KAAK,GAAG,CAAA;AAmB/B,IAAA,MAAA,CAAA,QAAA,EAAA,UAAA,CAAA;AA4BC,IAAA,MAAA,CAAA,UAAA,EAAA,YAAA,CAAA;AAiBM,IAAA,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;AC/Gf,SAAS,aAAA,CAAc,WAAW,QAAA,EAAU;AACjD,EAAA,MAAM,QAAQ,SAAA,GAAY,CAAA;AAE1B,EAAA,OAAO;AAAA,IACL,WAAW,SAAA,KAAc,CAAA;AAAA,IACzB,KAAA;AAAA,IACA,WAAW,QAAA,KAAa,CAAA,GAAI,CAAA,GAAK,KAAA,GAAQ,WAAW,CAAA,KAAO;AAAA,GAC7D;AACF;AAwDO,SAAS,iBAAA,CAAkB,QAAQ,UAAA,EAAY,QAAA,EAAU,WAAW,QAAA,EAAU,IAAA,EAAM,GAAA,EAAK,MAAA,GAAS,IAAA,EAAM;AAG7G,EAAA,MAAM,WAAA,GAAc,MAAA,KAAW,IAAA,GAAO,QAAA,GAAW,MAAA,CAAO,WAAA;AAKxD,EAAA,IAAI,aAAa,CAAA,EAAG;AAClB,IAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,QAAA,GAAW,CAAA,IAAK,QAAQ,WAAA,EAAa;AAC1D,MAAAK,OAAAA,CAAO,MAAA,EAAQ,CAAA,EAAG,IAAA,EAAM,IAAI,CAAA;AAAA,IAC9B;AAEA,IAAA,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,CAAA,EAAG,QAAQ,CAAA;AAC1B,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,MAAM,EAAC,SAAA,EAAW,KAAA,EAAO,WAAS,GAAI,aAAA,CAAc,WAAW,QAAQ,CAAA;AAEvE,EAAA,MAAM,OAAA,GAAU,KAAK,KAAK,CAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,KAAK,QAAQ,CAAA;AAK7B,EAAA,IAAI,IAAA,GAAO,SAAA;AAEX,EAAA,KAAA,IAAS,MAAM,CAAA,EAAG,GAAA,GAAM,QAAA,EAAU,GAAA,EAAA,EAAO,QAAQ,UAAA,EAAY;AAC3D,IAAA,IAAI,GAAA,GAAM,OAAO,IAAI,CAAA;AAErB,IAAA,IAAI,YAAY,CAAA,EAAG,GAAA,IAAO,MAAA,CAAO,IAAA,GAAO,CAAC,CAAA,GAAI,GAAA;AAC7C,IAAA,IAAI,YAAY,CAAA,EAAG,GAAA,IAAO,MAAA,CAAO,IAAA,GAAO,CAAC,CAAA,GAAI,KAAA;AAC7C,IAAA,IAAI,YAAY,CAAA,EAAG,GAAA,IAAO,MAAA,CAAO,IAAA,GAAO,CAAC,CAAA,GAAI,QAAA;AAC7C,IAAA,IAAI,YAAY,CAAA,EAAG,GAAA,IAAO,MAAA,CAAO,IAAA,GAAO,CAAC,CAAA,GAAI,UAAA;AAE7C,IAAA,MAAM,QAAS,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,OAAO,IAAI,OAAA,GAAW,IAAA;AAItD,IAAA,IAAA,CAAK,SAAS,WAAA,IAAgB,KAAA,GAAQ,KAAK,KAAA,KAAU,IAAA,KAAU,WAAW,IAAA,EAAM;AAC9E,MAAAA,OAAAA,CAAO,MAAA,EAAQ,GAAA,EAAK,KAAA,EAAO,IAAI,CAAA;AAAA,IACjC;AAEA,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AAAA,EACb;AAEA,EAAA,OAAO,GAAA;AACT;AAuBA,SAASA,OAAAA,CAAO,MAAA,EAAQ,GAAA,EAAK,KAAA,EAAO,IAAA,EAAM;AACxC,EAAA,MAAM,IAAI,kBAAkB,2BAAA,EAA6B;AAAA,IACvD,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,GAAA,EAAK,OAAO,QAAA,GAAW,GAAA;AAAA,IACvB,WAAA,EAAa,KAAA;AAAA,IACb,aAAa,MAAA,CAAO,WAAA;AAAA,IACpB,IAAA;AAAA,IACA,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,KAAA,EAAO;AAAA,GACR,CAAA;AACH;AAyBO,SAAS,aAAA,CAAc,MAAA,EAAQ,UAAA,EAAY,QAAA,EAAU,KAAA,EAAO;AACjE,EAAA,MAAM,EAAC,SAAA,EAAW,KAAA,EAAO,SAAA,EAAS,GAAI,QAAA;AAEtC,EAAA,IAAI,cAAc,CAAA,EAAG;AACnB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,OAAO,UAAA,GAAa,SAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,KAAA,GAAQ,IAAA,CAAK,KAAK,CAAA;AAElC,EAAA,MAAA,CAAO,IAAI,KAAK,OAAA,GAAU,GAAA;AAE1B,EAAA,IAAI,SAAA,GAAY,CAAA,EAAG,MAAA,CAAO,IAAA,GAAO,CAAC,KAAK,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,GAAK,CAAA,GAAI,GAAA;AACrE,EAAA,IAAI,SAAA,GAAY,CAAA,EAAG,MAAA,CAAO,IAAA,GAAO,CAAC,KAAK,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,KAAO,CAAA,GAAI,GAAA;AACvE,EAAA,IAAI,SAAA,GAAY,CAAA,EAAG,MAAA,CAAO,IAAA,GAAO,CAAC,KAAK,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,QAAS,CAAA,GAAI,GAAA;AACzE,EAAA,IAAI,SAAA,GAAY,CAAA,EAAG,MAAA,CAAO,IAAA,GAAO,CAAC,KAAK,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,UAAW,CAAA,GAAI,GAAA;AAC7E;AAlOA,IAgBa,aAAA,EAQP,IAAA;AAxBN,IAAA,aAAA,GAAA,KAAA,CAAA;AAAA,EAAA,sBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AAcO,IAAM,aAAA,GAAgB,EAAA;AAQ7B,IAAM,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,EAAC,MAAA,EAAQ,EAAA,EAAE,EAAG,CAAC,CAAA,EAAG,QAAA,KAAa,CAAA,IAAK,QAAQ,CAAA;AAiBpD,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAgEA,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAsEP,IAAA,MAAA,CAAAA,OAAAA,EAAA,QAAA,CAAA;AAmCO,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;AChGT,SAAS,kBAAkB,IAAA,EAAM;AACtC,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,WAAA,EAAa,IAAA,CAAK,GAAA,CAAI,kBAAA,EAAoB,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,CAAC,CAAC,CAAC,CAAA;AACjF;AAiCO,SAAS,MAAA,CAAO,OAAO,IAAA,EAAM;AAClC,EAAA,MAAM,UAAU,KAAA,GAAQ,UAAA;AAExB,EAAA,OAAO,OAAA,GAAU,KAAA,IAAS,OAAA,GAAU,CAAC,KAAA,GAAQ,OAAA,GAAU,IAAA,GAAA,CAAA,CAAS,OAAA,GAAU,CAAA,KAAO,OAAA,GAAU,UAAA,GAAc,CAAA,CAAA,IAAM,IAAA;AACjH;AASA,SAAS,QAAA,CAAS,OAAO,IAAA,EAAM;AAC7B,EAAA,IAAI,KAAA,GAAQ,SAAA;AAEZ,EAAA,OAAO,KAAA,GAAQ,KAAA,IAAS,KAAA,GAAQ,IAAA,EAAM;AACpC,IAAA,KAAA,IAAS,CAAA;AAAA,EACX;AAEA,EAAA,OAAO,KAAA;AACT;AAUO,SAAS,QAAQ,OAAA,EAAS;AAC/B,EAAA,IAAI,KAAA,GAAQ,SAAA;AAEZ,EAAA,OAAO,KAAA,GAAQ,SAAA,IAAa,KAAA,GAAQ,OAAA,GAAU,WAAA,EAAa;AACzD,IAAA,KAAA,IAAS,CAAA;AAAA,EACX;AAEA,EAAA,OAAO,KAAA;AACT;AAoKO,SAAS,eAAA,CAAgB,MAAM,IAAA,EAAM;AAC1C,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA,GACtB,IAAI,WAAA,CAAY,SAAA,EAAW,QAAA,CAAS,IAAA,EAAM,SAAS,CAAA,EAAG,sBAAA,EAAwB,IAAI,CAAA,GAClF,IAAA;AACN;AAgBO,SAAS,iBAAA,CAAkB,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,OAAA,EAAS;AAChE,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,GAAQ,IAAA,CAAK,SAAS,OAAA,CAAQ,GAAA;AAEnD,EAAA,IAAI,CAAC,cAAA,CAAe,OAAA,EAAS,IAAI,CAAA,EAAG;AAClC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,QAAQ,OAAA,CAAQ,KAAA;AAEpB,EAAA,KAAA,IAAS,MAAM,OAAA,CAAQ,GAAA,EAAK,GAAA,GAAM,IAAA,CAAK,QAAQ,GAAA,EAAA,EAAO;AACpD,IAAA,IAAI,OAAO,IAAA,CAAK,GAAG,CAAA,GAAI,MAAM,MAAM,QAAA,EAAU;AAC3C,MAAA,KAAA,EAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AASO,SAAS,UAAU,GAAA,EAAK;AAC7B,EAAA,IAAI,OAAA,GAAU,CAAA;AAEd,EAAA,KAAA,MAAW,GAAA,IAAO,GAAA,CAAI,IAAA,EAAK,EAAG;AAC5B,IAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,MAAA,OAAA,EAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AAUO,SAAS,cAAA,CAAe,SAAS,KAAA,EAAO;AAC7C,EAAA,OAAO,OAAA,GAAU,CAAA,IAAK,OAAA,IAAW,qBAAA,GAAwB,KAAA;AAC3D;AAYO,SAAS,cAAA,CAAe,OAAA,EAAS,KAAA,EAAO,OAAA,EAAS,OAAO,IAAA,EAAM;AACnE,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,OAAA,GAAU,gBAAA,EAAkB,KAAK,CAAA,EAAG,QAAA,CAAS,KAAA,EAAO,KAAK,CAAC,CAAA;AAE1F,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA,GAClB,IAAI,WAAA,CAAY,KAAA,EAAO,KAAA,EAAO,qBAAA,GAAwB,OAAA,GAAU,KAAA,EAAO,IAAA,EAAM,OAAO,CAAA,GACpF,IAAA;AACN;AAeO,SAAS,SAAA,CAAU,MAAA,EAAQ,GAAA,GAAM,CAAA,EAAG,UAAU,IAAA,EAAM;AACzD,EAAA,KAAA,IAAS,MAAA,GAAS,CAAA,EAAG,MAAA,GAAS,MAAA,CAAO,QAAQ,MAAA,EAAA,EAAU;AACrD,IAAA,MAAM,KAAA,GAAQ,OAAO,MAAM,CAAA;AAE3B,IAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,YAAA,EAAc;AAC5C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,GAAQ,KAAA,CAAM,WAAA;AAEpC,IAAA,IAAI,UAAU,kBAAA,EAAoB;AAChC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,MAAM,MAAA,GAAA,CAAU,KAAA,CAAM,SAAS,KAAA,CAAM,KAAA,GAAQ,2BAA2B,OAAA,EAAS;AACnF,MAAA,MAAA,CAAO,MAAM,CAAA,GAAI,IAAA;AACjB,MAAA,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,MAAM,CAAA;AAEnC,MAAA,IAAI,YAAY,IAAA,EAAM;AACpB,QAAA,OAAA,CAAQ,MAAM,CAAA,GAAI,EAAC,GAAA,EAAK,KAAA,EAAO,MAAM,KAAA,EAAK;AAAA,MAC5C;AAAA,IACF,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,cAAc,KAAA,CAAM,KAAA;AAC1B,MAAA,KAAA,CAAM,MAAA,GAAS,CAAA;AACf,MAAA,KAAA,CAAM,MAAA,GAAS,IAAA;AAAA,IACjB;AAAA,EACF;AACF;AA/dA,IA6FM,UAAA,EAGA,KAAA,EAGA,UAAA,EAGO,WAAA,EAGA,kBAAA,EAcA,SAAA,EAGA,SAAA,EAGA,WAAA,EAMP,gBAAA,EAGO,uBAAA,EAGA,sBAAA,EAGA,qBAAA,EAmDA,UAsCA,WAAA,EAgHA,YAAA;AArVb,IAAA,gBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,yBAAA,GAAA;AA6FA,IAAM,UAAA,GAAa,UAAA;AAGnB,IAAM,QAAQ,CAAA,IAAK,EAAA;AAGnB,IAAM,aAAa,CAAA,IAAK,GAAA;AAGjB,IAAM,WAAA,GAAc,KAAA;AAGpB,IAAM,kBAAA,GAAqB,IAAA;AASlB,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAKT,IAAM,SAAA,GAAY,EAAA;AAGlB,IAAM,SAAA,GAAY,KAAA;AAGlB,IAAM,cAAc,CAAA,IAAK,EAAA;AAMhC,IAAM,gBAAA,GAAmB,CAAA;AAGlB,IAAM,uBAAA,GAA0B,GAAA;AAGhC,IAAM,sBAAA,GAAyB,GAAA;AAG/B,IAAM,qBAAA,GAAwB,IAAA;AASrB,IAAA,MAAA,CAAA,MAAA,EAAA,QAAA,CAAA;AAaP,IAAA,MAAA,CAAA,QAAA,EAAA,UAAA,CAAA;AAkBO,IAAA,MAAA,CAAA,OAAA,EAAA,SAAA,CAAA;AAWT,IAAM,WAAN,MAAe;AAAA,MA/LtB;AA+LsB,QAAA,MAAA,CAAA,IAAA,EAAA,UAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAIpB,WAAA,CAAY,QAAQ,WAAA,EAAa;AAE/B,QAAA,IAAA,CAAK,IAAA,GAAO,KAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,KAAK,KAAA,EAAO;AACV,QAAA,IAAI,KAAA,GAAQ,KAAK,IAAA,EAAM;AACrB,UAAA,OAAO,KAAA;AAAA,QACT;AAEA,QAAA,IAAA,CAAK,IAAA,IAAQ,KAAA;AAEb,QAAA,OAAO,IAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,KAAK,KAAA,EAAO;AACV,QAAA,IAAA,CAAK,IAAA,IAAQ,KAAA;AAAA,MACf;AAAA,KACF;AAKO,IAAM,WAAA,GAAN,MAAM,YAAA,CAAY;AAAA,MArOzB;AAqOyB,QAAA,MAAA,CAAA,IAAA,EAAA,aAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUvB,YAAY,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,IAAA,EAAM,UAAU,EAAA,EAAI;AAEtD,QAAA,IAAA,CAAK,SAAS,IAAI,YAAA,CAAa,KAAK,CAAA,CAAE,KAAK,GAAG,CAAA;AAE9C,QAAA,IAAA,CAAK,UAAU,IAAI,UAAA,CAAW,OAAA,IAAW,CAAA,GAAI,QAAQ,CAAC,CAAA;AAMtD,QAAA,IAAA,CAAK,GAAA,GAAM,IAAI,WAAA,CAAY,OAAA,IAAW,CAAA,GAAI,KAAK,IAAA,CAAK,OAAA,GAAU,EAAE,CAAA,GAAI,CAAC,CAAA;AAErE,QAAA,IAAA,CAAK,OAAO,KAAA,GAAQ,CAAA;AAEpB,QAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAEhB,QAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AAEb,QAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAKZ,QAAA,IAAA,CAAK,KAAA,GAAQ,CAAA;AAEb,QAAA,IAAA,CAAK,WAAA,GAAc,CAAA;AAKnB,QAAA,IAAA,CAAK,MAAA,GAAS,CAAA;AAKd,QAAA,IAAA,CAAK,SAAS,OAAA,IAAW,CAAA;AAMzB,QAAA,IAAA,CAAK,QAAA,GAAW,CAAA;AAAA,MAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,QAAA,CAAS,MAAM,KAAA,EAAO;AACpB,QAAA,IAAA,CAAK,QAAA,EAAA;AAEL,QAAA,IAAI,IAAA,CAAK,QAAA,GAAW,gBAAA,GAAmB,IAAA,CAAK,MAAA,CAAO,UAAU,IAAA,CAAK,MAAA,CAAO,MAAA,GAAS,IAAA,CAAK,QAAA,EAAU;AAC/F,UAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,CAAI,IAAA,CAAK,OAAO,MAAA,GAAS,CAAA,EAAG,KAAK,QAAQ,CAAA;AAE5D,UAAA,IAAI,KAAK,IAAA,CAAK,IAAA,CAAK,QAAQ,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,EAAG;AAE9C,YAAA,MAAM,KAAA,GAAQ,IAAI,YAAA,CAAY,KAAA,EAAO,KAAK,QAAA,EAAU,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,IAAI,CAAA;AAEzE,YAAA,KAAA,CAAM,WAAW,IAAA,CAAK,QAAA;AACtB,YAAA,KAAA,CAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,YAAA,KAAA,CAAM,cAAc,IAAA,CAAK,WAAA;AACzB,YAAA,KAAA,CAAM,SAAS,IAAA,CAAK,MAAA;AACpB,YAAA,KAAA,CAAM,SAAS,IAAA,CAAK,MAAA;AAEpB,YAAA,OAAO,KAAA;AAAA,UACT;AAEA,UAAA,IAAA,CAAK,QAAA,GAAW,KAAK,MAAA,CAAO,MAAA;AAAA,QAC9B;AAEA,QAAA,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,GAAI,KAAA;AAEpB,QAAA,OAAO,IAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,UAAU,KAAA,EAAO;AACf,QAAA,MAAM,OAAO,KAAA,KAAU,CAAA;AACvB,QAAA,MAAM,GAAA,GAAM,MAAM,KAAA,GAAQ,EAAA,CAAA;AAC1B,QAAA,MAAM,MAAA,GAAA,CAAU,IAAA,CAAK,GAAA,CAAI,IAAI,IAAI,GAAA,MAAS,CAAA;AAE1C,QAAA,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,IAAK,GAAA;AAElB,QAAA,OAAO,MAAA;AAAA,MACT;AAAA,KACF;AAOO,IAAM,YAAA,GAAe,IAAI,WAAA,CAAY,CAAA,EAAG,GAAG,CAAA,EAAG,IAAI,QAAA,CAAS,CAAC,CAAC,CAAA;AAWpD,IAAA,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAoBA,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAyBA,IAAA,MAAA,CAAA,SAAA,EAAA,WAAA,CAAA;AAoBA,IAAA,MAAA,CAAA,cAAA,EAAA,gBAAA,CAAA;AAcA,IAAA,MAAA,CAAA,cAAA,EAAA,gBAAA,CAAA;AAqBA,IAAA,MAAA,CAAA,SAAA,EAAA,WAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACpchB,IAAA,qBAAA,GAAA,EAAA;AAAA,QAAA,CAAA,qBAAA,EAAA;AAAA,EAAA,aAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAgEA,SAAS,YAAY,KAAA,EAAO;AAC1B,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,KAAA,CAAM,QAAQ,KAAA,EAAA,EAAS;AACjD,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,CAAW,KAAK,CAAA;AAEnC,IAAA,IAAK,IAAA,GAAO,EAAA,IAAQ,IAAA,KAAS,CAAA,IAAQ,IAAA,KAAS,EAAA,IAAQ,IAAA,KAAS,EAAA,IAAS,IAAA,KAAS,KAAA,IAAU,IAAA,KAAS,KAAA,EAAQ;AAC1G,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,EAAA;AACT;AAiBA,SAAS,eAAA,CAAgB,KAAA,EAAO,OAAA,EAAS,OAAA,EAAS;AAChD,EAAA,SAAA,CAAU,KAAA,EAAO,SAAS,OAAO,CAAA;AAEjC,EAAA,MAAM,QAAA,GAAW,YAAY,KAAK,CAAA;AAElC,EAAA,IAAI,aAAa,EAAA,EAAI;AACnB,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,CAAW,QAAQ,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,WAAA,EAAY,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAA;AAElF,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,EAAG,OAAO,CAAA,kBAAA,EAAqB,IAAI,CAAA,uBAAA,CAAA,EAA2B,EAAC,GAAG,OAAA,EAAS,QAAA,EAAS,CAAA;AAAA,EACnH;AACF;AAYA,SAAS,gBAAA,CAAiB,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,OAAA,EAAS;AACzD,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,eAAA,CAAgB,KAAA,EAAO,CAAA,IAAA,EAAO,QAAQ,CAAA,IAAA,EAAO,KAAK,IAAI,EAAC,GAAG,OAAA,EAAS,QAAA,EAAS,CAAA;AAAA,EAC9E,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/B,IAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU,gBAAA,CAAiB,IAAA,EAAM,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,CAAA,EAAK,KAAA,EAAO,OAAO,CAAC,CAAA;AAAA,EAChG,CAAA,MAAA,IAAW,KAAA,KAAU,IAAA,IAAQ,OAAO,UAAU,QAAA,EAAU;AACtD,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/C,MAAA,gBAAA,CAAiB,MAAM,CAAA,EAAG,QAAQ,IAAI,GAAG,CAAA,CAAA,EAAI,OAAO,OAAO,CAAA;AAAA,IAC7D;AAAA,EACF;AACF;AAgBA,SAAS,mBAAA,CAAoB,SAAS,QAAA,EAAU;AAE9C,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAI;AAErB,EAAA,OAAA,CAAQ,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU;AAC/B,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,CAAK,WAAW,CAAA,EAAG;AACjD,MAAA,MAAM,IAAI,mBAAmB,uCAAA,EAAyC;AAAA,QACpE,MAAA,EAAQ,KAAA;AAAA,QACR,QAAA,EAAU,IAAA;AAAA,QACV,MAAM,OAAO,IAAA;AAAA,QACb,IAAA,EAAM,QAAA;AAAA,QACN,KAAA,EAAO;AAAA,OACR,CAAA;AAAA,IACH;AAEA,IAAA,eAAA,CAAgB,IAAA,EAAM,cAAA,EAAgB,EAAC,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAU,IAAA,EAAM,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,kBAAA,EAAmB,CAAA;AAEhH,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,EAAG;AAClB,MAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,OAAA,EAAU,IAAI,CAAA,eAAA,CAAA,EAAmB;AAAA,QAC5D,MAAA,EAAQ,IAAA;AAAA,QACR,WAAA,EAAa,KAAA;AAAA,QACb,IAAA,EAAM,QAAA;AAAA,QACN,KAAA,EAAO;AAAA,OACR,CAAA;AAAA,IACH;AAEA,IAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA,EACf,CAAC,CAAA;AACH;AA+BA,SAAS,UAAA,CAAW,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,QAAA,EAAU;AAChD,EAAA,IAAI,aAAA,GAAgB,KAAA;AAEpB,EAAA,IAAI;AACF,IAAA,aAAA,GACE,KAAA,KAAU,IAAA,IACV,OAAO,KAAA,KAAU,QAAA,KAChB,QAAA,IAAY,KAAA,IAAS,MAAA,IAAU,KAAA,IAAU,UAAA,IAAc,KAAA,IAAS,aAAA,IAAiB,KAAA,CAAA;AAAA,EACtF,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,MAAM,IAAI,kBAAA;AAAA,IACR,6DAA6D,YAAA,CAAa,KAAK,CAAC,CAAA,uNAAA,CAAA,IAG7E,gBAAgB,+EAAA,GAAkF,EAAA,CAAA;AAAA,IACrG;AAAA,MACE,MAAA;AAAA,MACA,GAAA;AAAA,MACA,MAAM,OAAO,KAAA;AAAA,MACb,WAAA,EAAa,eAAA,CAAgB,KAAK,CAAA,IAAK,MAAA;AAAA,MACvC,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA;AACT,GACF;AACF;AAkEA,SAAS,iBAAiB,KAAA,EAAO;AAC/B,EAAA,MAAM,EAAC,MAAA,EAAQ,OAAA,EAAO,GAAI,KAAA;AAG1B,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,CAAO,QAAQ,KAAA,EAAA,EAAS;AAClD,IAAA,IAAI,CAAC,cAAc,MAAA,CAAO,KAAK,GAAG,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG;AACjD,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAWA,SAAS,OAAA,CAAQ,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM;AAClC,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,CAAK,MAAA;AAEzB,EAAA,MAAA,CAAO,IAAA,CAAK,KAAK,GAAG,CAAA;AACpB,EAAA,MAAA,CAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AAGtB,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,MAAA,CAAO,MAAM,SAAA,GAAY,IAAA;AACzB,IAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA,EAAG,MAAA,CAAO,MAAM,WAAA,GAAc,IAAA;AAAA,EACzD,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,MAAM,YAAA,GAAe,IAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,IAAA;AACT;AAeA,SAAS,OAAA,CAAQ,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM;AAClC,EAAA,IAAI,IAAA,GAAO,MAAA,CAAO,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAE/B,EAAA,IAAI,SAAS,MAAA,EAAW;AACtB,IAAA,IAAA,GAAO,OAAA,CAAQ,MAAA,EAAQ,GAAA,EAAK,IAAI,CAAA;AAChC,IAAA,MAAA,CAAO,KAAA,CAAM,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAAA,EAC5B,CAAA,MAAA,IAAW,IAAA,KAAS,IAAA,IAAQ,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,KAAM,IAAA,IAAQ,OAAO,GAAA,KAAQ,QAAA,EAAU;AAClF,IAAA,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,GAAI,IAAA;AAAA,EACvB;AAEA,EAAA,OAAO,IAAA;AACT;AAYA,SAAS,gBAAA,CAAiB,OAAA,EAAS,OAAA,EAAS,KAAA,EAAO;AAEjD,EAAA,IAAI,MAAA,GAAS,IAAA;AAEb,EAAA,IAAI,MAAA,GAAS,IAAA;AAEb,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,IAAI,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAA,EAAM;AAC3B,MAAA,IAAI,WAAW,IAAA,EAAM;AACnB,QAAA,MAAA,GAAS,QAAQ,KAAK,CAAA;AAAA,MACxB,WAAW,CAAC,aAAA,CAAc,QAAQ,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG;AACjD,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,CAAA,MAAA,IAAW,WAAW,IAAA,EAAM;AAC1B,MAAA,MAAA,GAAS,MAAM,KAAK,CAAA;AAAA,IACtB,CAAA,MAAA,IAAW,MAAA,KAAW,KAAA,CAAM,KAAK,CAAA,EAAG;AAClC,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,MAAA,KAAW,QAAQ,MAAA,KAAW,IAAA;AACvC;AAmBA,SAAS,yBAAyB,KAAA,EAAO;AACvC,EAAA,MAAM,EAAC,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAK,GAAI,KAAA;AAEjC,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,CAAO,QAAQ,KAAA,EAAA,EAAS;AAClD,IAAA,IAAI,OAAO,MAAA,CAAO,KAAK,CAAA,KAAM,QAAA,IAAY,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAA,IAAQ,KAAA,CAAM,KAAK,CAAA,KAAM,IAAA,EAAM;AAEzF,MAAA,IAAI,CAAC,aAAA,CAAc,KAAA,CAAM,KAAK,CAAC,CAAA,EAAG;AAChC,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAI;AAExB,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,CAAO,QAAQ,KAAA,EAAA,EAAS;AAClD,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAK,CAAA,IAAK,QAAQ,KAAK,CAAA;AAC3C,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AAEjC,IAAA,IAAI,YAAY,MAAA,EAAW;AACzB,MAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,EAAO,CAAC,KAAK,CAAC,CAAA;AAAA,IAC5B,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,OAAA,IAAW,OAAA,CAAQ,MAAA,EAAO,EAAG;AACtC,IAAA,IAAI,QAAQ,MAAA,GAAS,CAAA,IAAK,iBAAiB,OAAA,EAAS,OAAA,EAAS,KAAK,CAAA,EAAG;AACnE,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAcA,SAAS,wBAAwB,MAAA,EAAQ;AAEvC,EAAA,MAAM,EAAC,OAAA,EAAS,KAAA,EAAK,GAAI,MAAA,CAAO,KAAA;AAGhC,EAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC3C,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,MAAA,CAAO,CAAuB,KAAA,KAAU,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAA,IAAQ,KAAA,CAAM,KAAK,CAAA,KAAM,IAAI,CAAA;AAE3G,MAAA,IAAI,KAAK,MAAA,GAAS,CAAA,IAAK,iBAAiB,IAAA,EAAM,OAAA,EAAS,KAAK,CAAA,EAAG;AAC7D,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAgCA,SAAS,gBAAgB,MAAA,EAAQ;AAE/B,EAAA,MAAM,EAAC,MAAA,EAAQ,OAAA,EAAS,KAAA,KAAS,MAAA,CAAO,KAAA;AACxC,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,KAAA,GAAQ,KAAA;AAGZ,EAAA,KAAA,MAAW,CAAC,KAAA,EAAO,KAAK,CAAA,IAAK,OAAO,OAAA,EAAS;AAC3C,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,iBAAiB,KAAA,EAAO,OAAA,EAAS,KAAK,CAAA,EAAG;AAGxE,MAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,QAAA,OAAA,GAAU,IAAA;AAAA,MACZ,CAAA,MAAO;AACL,QAAA,KAAA,GAAQ,IAAA;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,8DAAA;AAAA,EACT;AAKA,EAAA,IAAI,CAAC,KAAA,IAAS,CAAC,wBAAA,CAAyB,MAAA,CAAO,KAAK,CAAA,EAAG;AACrD,IAAA,OAAO,sDAAA;AAAA,EACT;AAEA,EAAA,IAAI,uBAAA,CAAwB,MAAM,CAAA,EAAG;AACnC,IAAA,OAAO,sCAAA;AAAA,EACT;AAGA,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,CAAC,KAAA,EAAO,KAAA,KAAU,OAAO,KAAA,KAAU,QAAA,IAAY,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAI,IACrF,+EAAA,GACA,4HAAA;AAEN;AAwBA,SAAS,WAAA,CAAY,MAAA,EAAQ,KAAA,EAAO,GAAA,EAAK,QAAA,EAAU;AAIjD,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,MAAA,CAAO,KAAA,EAAO;AAClC,IAAA,OAAO,OAAA,CAAQ,MAAA,EAAQ,KAAA,EAAO,MAAA,CAAO,YAAA,KAAiB,IAAA,GAAO,IAAA,GAAQ,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA,IAAK,IAAK,CAAA;AAAA,EAC9G;AAGA,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AAEtC,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,OAAO,OAAA,CAAQ,MAAA,EAAQ,KAAA,EAAO,IAAI,CAAA;AAAA,EACpC;AAGA,EAAA,MAAM,EAAC,OAAA,EAAS,KAAA,EAAK,GAAI,MAAA,CAAO,KAAA;AAChC,EAAA,MAAM,UAAU,OAAO,KAAA,KAAU,QAAA,GAAW,CAAC,KAAK,CAAA,GAAI,KAAA;AAEtD,EAAA,IAAI,gBAAA,CAAiB,OAAA,EAAS,OAAA,EAAS,KAAK,CAAA,EAAG;AAE7C,IAAA,MAAM,SAAS,EAAC;AAEhB,IAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,MAAA,IAAI,CAAC,MAAA,CAAO,IAAA,CAAK,CAAC,IAAA,KAAS,cAAc,IAAA,CAAK,MAAA,EAAQ,OAAA,CAAQ,KAAK,CAAC,CAAA,IAAK,IAAA,CAAK,SAAS,KAAA,CAAM,KAAK,CAAC,CAAA,EAAG;AACpG,QAAA,MAAA,CAAO,IAAA,CAAK,EAAC,MAAA,EAAQ,OAAA,CAAQ,KAAK,GAAG,IAAA,EAAM,KAAA,CAAM,KAAK,CAAA,EAAE,CAAA;AAAA,MAC1D;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,kBAAA;AAAA,MACR,aAAa,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,cAAc,MAAA,CAAO,IAAI,CAAA,OAAA,EAAU,GAAG,mBAAmB,MAAA,CAAO,MAAM,CAAA,4EAAA,EACxB,eAAA,CAAgB,MAAM,CAAC,CAAA,CAAA;AAAA,MACvG,EAAC,MAAA,EAAQ,MAAA,CAAO,IAAA,EAAM,GAAA,EAAK,OAAO,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,KAAA,EAAO,kBAAA;AAAkB,KACrF;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,GAAS,IAAA;AAEb,EAAA,IAAI,UAAA,GAAa,IAAA;AAEjB,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAE3B,IAAA,IAAI,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAA,EAAM;AAE3B,MAAA,OAAO,OAAA,CAAQ,MAAA,EAAQ,KAAA,CAAM,KAAK,GAAG,IAAI,CAAA;AAAA,IAC3C;AAEA,IAAA,MAAA,KAAW,QAAQ,KAAK,CAAA;AACxB,IAAA,UAAA,KAAe,MAAM,KAAK,CAAA;AAAA,EAC5B;AAGA,EAAA,OAAO,OAAA,CAAQ,MAAA,EAAQ,MAAA,EAAQ,UAAU,CAAA;AAC3C;AAeA,SAAS,aAAA,CAAc,MAAA,EAAQ,KAAA,EAAO,GAAA,EAAK,QAAA,EAAU;AACnD,EAAA,MAAM,IAAA,GAAO,OAAO,KAAK,CAAA;AAEzB,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,UAAA,CAAW,KAAA,EAAO,MAAA,CAAO,IAAA,EAAM,GAAA,EAAK,QAAQ,CAAA;AAAA,EAC9C;AAEA,EAAA,MAAM,EAAC,MAAA,EAAQ,IAAA,EAAI,GAAI,IAAA;AAGvB,EAAA,IAAI,aAAA,CAAc,MAAM,CAAA,KAAM,IAAA,EAAM;AAClC,IAAA,WAAA,CAAY,QAAQ,4BAAA,EAA8B;AAAA,MAChD,QAAQ,MAAA,CAAO,IAAA;AAAA,MACf,GAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,WAAA,CAAY,IAAI,CAAA,KAAM,IAAA,EAAM;AAC9B,IAAA,SAAA,CAAU,MAAM,0BAAA,EAA4B;AAAA,MAC1C,QAAQ,MAAA,CAAO,IAAA;AAAA,MACf,GAAA;AAAA,MACA,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,MAAA,EAAQ,MAAA,EAAQ,IAAI,CAAA;AAEzC,EAAA,IAAI,OAAO,QAAA,CAAS,IAAA,GAAO,mBAAmB,CAAA,GAAI,MAAA,CAAO,KAAK,MAAA,EAAQ;AACpE,IAAA,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,KAAA,EAAO,IAAI,CAAA;AAAA,EACjC;AAEA,EAAA,OAAO,IAAA;AACT;AAkDA,SAAS,qBAAA,CAAsB,MAAM,KAAA,EAAO;AAC1C,EAAA,IAAI,IAAA,KAAS,QAAQ,OAAO,IAAA,KAAS,YAAY,IAAA,CAAK,MAAA,KAAW,MAAA,IAAa,KAAA,KAAU,MAAA,EAAW;AACjG,IAAA,OAAO,QAAQ,EAAC;AAAA,EAClB;AAEA,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,MAAM,IAAI,IAAA,CAAK,MAAA,GAAS,CAAC,IAAA,CAAK,MAAM,CAAA;AACpE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,CAAuB,GAAA,KAAQ;AACtD,IAAA,IAAI,MAAM,YAAA,IAAgB,YAAA,CAAa,GAAA,CAAI,GAAG,GAAG,OAAO,KAAA;AACxD,IAAA,IAAI,MAAM,WAAA,IAAe,iBAAA,CAAkB,GAAA,CAAI,GAAG,GAAG,OAAO,KAAA;AAC5D,IAAA,IAAI,MAAM,SAAA,IAAa,SAAA,CAAU,GAAA,CAAI,GAAG,GAAG,OAAO,KAAA;AAClD,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,IAAA,CAAK,MAAA,EAAQ;AAC/B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA,CAAK,WAAW,CAAA,GAAI,KAAK,EAAC,GAAG,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAI;AACxD;AAcA,SAAS,6BAAA,CAA8B,cAAc,KAAA,EAAO;AAC1D,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,OAAO,EAAC,GAAG,qBAAA,EAAqB;AAAA,EAClC;AAEA,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,CAAC,KAAA,CAAM,SAAA,IAAa,KAAA,CAAM,YAAA,IAAgB,eAAA,CAAgB,GAAA,CAAI,YAAA,CAAa,IAAI,CAAA,EAAG;AAC3G,IAAA,OAAO,EAAC,GAAG,qBAAA,EAAqB;AAAA,EAClC;AAEA,EAAA,OAAO,YAAA;AACT;AAzvBA,IA4OM,kBAobA,YAAA,CAAA,CAGA,SAAA,CAAA,CAGA,iBAAA,CAAA,CAGA,eAAA,CAAA,CAGA,uBAqFA,gBAAA,CAAA,CAEO;AAnwBb,IAAA,kBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,sBAAA,GAAA;AAeA,IAAA,cAAA,EAAA;AACA,IAAA,iBAAA,EAAA;AACA,IAAA,aAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AACA,IAAA,aAAA,EAAA;AACA,IAAA,cAAA,EAAA;AAUA,IAAA,gBAAA,EAAA;AACA,IAAA,kBAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AA8BS,IAAA,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AA2BA,IAAA,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAsBA,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AA0BA,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AA2DA,IAAA,MAAA,CAAA,UAAA,EAAA,YAAA,CAAA;AAsCT,IAAM,gBAAA,GAAmB,EAAA;AAsDhB,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAsBA,IAAA,MAAA,CAAA,OAAA,EAAA,SAAA,CAAA;AA8BA,IAAA,MAAA,CAAA,OAAA,EAAA,SAAA,CAAA;AAuBA,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAwCA,IAAA,MAAA,CAAA,wBAAA,EAAA,0BAAA,CAAA;AA+CA,IAAA,MAAA,CAAA,uBAAA,EAAA,yBAAA,CAAA;AAgDA,IAAA,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AA+DA,IAAA,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAqEA,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAwCT,IAAM,YAAA,uBAAmB,GAAA,CAAI,CAAC,YAAY,UAAA,EAAY,OAAA,EAAS,OAAA,EAAS,YAAY,CAAC,CAAA;AAGrF,IAAM,4BAAY,IAAI,GAAA,CAAI,CAAC,OAAA,EAAS,QAAQ,CAAC,CAAA;AAG7C,IAAM,oCAAoB,IAAI,GAAA,CAAI,CAAC,UAAA,EAAY,OAAO,CAAC,CAAA;AAGvD,IAAM,eAAA,mBAAkB,IAAI,GAAA,CAAI,CAAC,SAAA,EAAW,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,WAAA,EAAa,UAAU,CAAC,CAAA;AAG5G,IAAM,wBAAwB,MAAA,CAAO,MAAA,CAAO,EAAC,IAAA,EAAM,WAAW,IAAA,EAAM,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,KAAK,EAAA,EAAI,GAAA,EAAK,EAAA,EAAI,IAAA,EAAM,IAAG,CAAA;AAmCzG,IAAA,MAAA,CAAA,qBAAA,EAAA,uBAAA,CAAA;AAgCA,IAAA,MAAA,CAAA,6BAAA,EAAA,+BAAA,CAAA;AAkBT,IAAM,gBAAA,GAAmB,MAAM,IAAA,GAAO,IAAA;AAE/B,IAAM,gBAAN,MAAoB;AAAA,MAnwB3B;AAmwB2B,QAAA,MAAA,CAAA,IAAA,EAAA,eAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA8BzB,WAAA,CAAY,QAAA,EAAU,EAAA,EAAI,OAAA,GAAU,EAAC,EAAG;AACtC,QAAA,MAAM,EAAC,UAAA,EAAY,UAAA,EAAY,MAAA,EAAQ,OAAK,GAAI,OAAA;AAChD,QAAA,MAAM,OAAA,GAAU,SAAA,CAAU,QAAA,EAAU,UAAU,CAAA;AAC9C,QAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,IAAA;AAMrB,QAAA,IAAA,CAAK,cAAc,OAAA,CAAQ,IAAA;AAG3B,QAAA,IAAA,CAAK,OAAA,GAAU,aAAA,CAAc,MAAA,EAAQ,EAAC,MAAA,EAAQ,QAAA,EAAU,IAAA,EAAM,IAAA,CAAK,KAAA,EAAO,SAAA,EAAW,IAAA,EAAK,CAAA;AAC1F,QAAA,IAAA,CAAK,MAAA,GAAS,aAAA,CAAc,KAAA,EAAO,EAAC,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAM,IAAA,CAAK,KAAA,EAAO,SAAA,EAAW,IAAA,EAAK,CAAA;AACvF,QAAA,IAAA,CAAK,GAAA,GAAM,EAAA;AACX,QAAA,IAAA,CAAK,WAAA,GAAc,UAAA;AACnB,QAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,QAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AAOrB,QAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AAErB,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAEpB,QAAA,IAAA,CAAK,oBAAA,GAAuB,IAAA;AAC5B,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAgBpB,QAAA,IAAA,CAAK,mBAAA,GAAsB,IAAA;AAE3B,QAAA,IAAA,CAAK,mBAAA,GAAsB,IAAA;AAE3B,QAAA,IAAA,CAAK,YAAA,GAAe,CAAA;AACpB,QAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AAAA,MACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,aAAA,CAAc,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO;AACnC,QAAA,IAAI,KAAK,WAAA,EAAa;AACpB,UAAA,MAAM,OAAA,GAAU,QAAQ,CAAA,GAAI,IAAA,CAAK,MAAO,OAAA,GAAU,KAAA,GAAS,GAAG,CAAA,GAAI,GAAA;AAClE,UAAA,IAAA,CAAK,WAAA,CAAY;AAAA,YACf,KAAA;AAAA,YACA,OAAA;AAAA,YACA,KAAA;AAAA,YACA;AAAA,WACD,CAAA;AAAA,QACH;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,UAAA,GAAa;AACjB,QAAAH,OAAAA,CAAO,IAAA,CAAK,OAAA,EAAS,0CAA0C,CAAA;AAC/D,QAAAA,OAAAA,CAAO,IAAA,CAAK,aAAA,EAAe,gDAAgD,CAAA;AAC3E,QAAAA,OAAAA,CAAO,IAAA,CAAK,YAAA,EAAc,+CAA+C,CAAA;AAEzE,QAAA,IAAA,CAAK,aAAA,CAAc,OAAA,EAAS,CAAA,EAAG,CAAC,CAAA;AAGhC,QAAA,MAAM,eAAe,MAAA,CAAO,MAAA,CAAO,CAAC,MAAA,CAAO,KAAK,IAAA,CAAK,OAAA,EAAS,OAAO,CAAA,EAAG,OAAO,IAAA,CAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAOzF,QAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,IAAA,CAAK,KAAA,EAAO,OAAO,CAAA;AACnD,QAAA,MAAM,WAAA,GAAc,KAAK,YAAA,EAAa;AAEtC,QAAA,IAAI,YAAY,OAAA,EAAS;AACvB,UAAA,MAAM,IAAA,CAAK,YAAA,CAAa,WAAA,EAAa,YAAA,EAAc,MAAM,CAAA;AAAA,QAC3D,CAAA,MAAO;AACL,UAAA,MAAM,IAAA,CAAK,aAAA,CAAc,WAAA,EAAa,YAAA,EAAc,MAAM,CAAA;AAAA,QAC5D;AAIA,QAAA,IAAA,CAAK,aAAA,CAAc,OAAA,EAAS,CAAA,EAAG,CAAC,CAAA;AAAA,MAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBA,YAAA,GAAe;AAKb,QAAA,MAAM,OAAA,GAAU,SAAA,CAAU,IAAA,CAAK,KAAA,EAAO,KAAK,WAAW,CAAA;AACtD,QAAA,MAAM,WAAW,OAAA,CAAQ,KAAA;AAQzB,QAAA,MAAM,OAAA,GAAU,QAAA,KAAa,IAAA,IAAQ,CAAC,SAAS,MAAA,EAAO;AAQtD,QAAA,MAAM,OAAA,GAAA,CAAW,IAAA,CAAK,OAAA,IAAW,QAAA,KAAa,SAAS,CAAC,OAAA;AAExD,QAAA,OAAO;AAAA,UACL,OAAA;AAAA,UACA,MAAM,OAAA,CAAQ,MAAA;AAAA,UACd,QAAA;AAAA,UACA,OAAA;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,MAAA,IAAU,CAAC;AAAA,SACxB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAoBA,MAAM,aAAA,CAAc,WAAA,EAAa,YAAA,EAAc,MAAA,EAAQ;AAGrD,QAAA,MAAM,KAAK,MAAM,WAAA,CAAY,WAAA,CAAY,OAAA,EAAS,WAAW,MAAM,CAAA;AAEnE,QAAA,MAAM,UAAA,CAAW,EAAA,EAAI,MAAA,EAAQ,YAAY;AACvC,UAAA,MAAM,IAAA,CAAK,WAAA,CAAY,EAAA,EAAI,YAAA,EAAc,MAAM,CAAA;AAE/C,UAAA,IAAI,YAAY,IAAA,EAAM;AACpB,YAAA,MAAM,EAAA,CAAG,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,CAAA;AAAA,UAC9B;AAAA,QACF,CAAC,CAAA;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBA,MAAM,YAAA,CAAa,WAAA,EAAa,YAAA,EAAc,MAAA,EAAQ;AACpD,QAAA,MAAM,SAAA,GAAY,gBAAA,CAAiB,WAAA,CAAY,IAAI,CAAA;AAOnD,QAAA,MAAM,IAAA,GAAO,WAAA,CAAY,QAAA,KAAa,IAAA,GAAO,MAAA,GAAY,GAAA;AACzD,QAAA,MAAM,EAAA,GAAK,MAAMF,GAAAA,CAAG,QAAA,CAAS,IAAA,CAAK,WAAW,IAAA,EAAM,IAAI,CAAA,CAAE,KAAA,CAAM,MAAM,CAAA;AAErE,QAAA,IAAI;AACF,UAAA,MAAM,UAAA,CAAW,EAAA,EAAI,MAAA,EAAQ,YAAY;AACvC,YAAA,MAAM,IAAA,CAAK,WAAA,CAAY,EAAA,EAAI,YAAA,EAAc,MAAM,CAAA;AAM/C,YAAA,IAAI,WAAA,CAAY,QAAA,KAAa,IAAA,IAAQ,OAAA,CAAQ,aAAa,OAAA,EAAS;AAGjE,cAAA,MAAM,EAAA,CAAG,KAAA,CAAM,MAAA,CAAO,WAAA,CAAY,QAAA,CAAS,IAAI,CAAA,GAAI,GAAK,CAAA,CAAE,KAAA,CAAM,MAAM,CAAA;AAAA,YACxE;AAIA,YAAA,IAAI,YAAY,IAAA,EAAM;AACpB,cAAA,MAAM,EAAA,CAAG,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,CAAA;AAAA,YAC9B;AAAA,UACF,CAAC,CAAA;AAED,UAAA,MAAM,WAAW,SAAA,EAAW,WAAA,CAAY,IAAI,CAAA,CAAE,MAAM,MAAM,CAAA;AAAA,QAC5D,SAAS,KAAA,EAAO;AAEd,UAAA,MAAM,OAAA,GAAU,MAAM,eAAA,CAAgB,SAAS,CAAA;AAU/C,UAAA,MAAM,OAAA;AAAA;AAAA,YAA8D,KAAA,EAAQ;AAAA,WAAA;AAC5E,UAAA,IAAI,CAAC,OAAA,IAAW,OAAA,KAAY,IAAA,IAAQ,OAAO,YAAY,QAAA,IAAY,MAAA,CAAO,YAAA,CAAa,OAAO,CAAA,EAAG;AAC/F,YAAA,OAAA,CAAQ,aAAA,GAAgB,SAAA;AAAA,UAC1B;AAEA,UAAA,MAAM,KAAA;AAAA,QACR;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,MAAM,WAAA,CAAY,EAAA,EAAI,YAAA,EAAc,MAAA,EAAQ;AAC1C,QAAA,MAAM,IAAA,CAAK,WAAA,CAAY,EAAA,EAAI,YAAA,EAAc,GAAG,MAAM,CAAA;AAClD,QAAA,MAAM,KAAK,WAAA,CAAY,EAAA,EAAI,KAAK,aAAA,EAAe,YAAA,CAAa,QAAQ,MAAM,CAAA;AAC1E,QAAA,MAAM,IAAA,CAAK,WAAA,CAAY,EAAA,EAAI,IAAA,CAAK,YAAA,EAAc,aAAa,MAAA,GAAS,IAAA,CAAK,aAAA,CAAc,MAAA,EAAQ,MAAM,CAAA;AAAA,MACvG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA2BA,MAAM,WAAA,CAAY,EAAA,EAAI,MAAA,EAAQ,cAAc,MAAA,EAAQ;AAClD,QAAA,IAAI,IAAA,GAAO,CAAA;AAEX,QAAA,OAAO,IAAA,GAAO,OAAO,MAAA,EAAQ;AAC3B,UAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAI,gBAAA,EAAkB,MAAA,CAAO,SAAS,IAAI,CAAA;AAC9D,UAAA,MAAM,EAAC,YAAA,EAAY,GAAI,MAAM,EAAA,CAAG,KAAA,CAAM,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAQ,YAAA,GAAe,IAAI,CAAA,CAAE,MAAM,MAAM,CAAA;AAI7F,UAAA,IAAI,EAAE,eAAe,CAAA,CAAA,EAAI;AACvB,YAAA,MAAM,IAAI,UAAA;AAAA,cACR,CAAA,0DAAA,EAA6D,eAAe,IAAI,CAAA,6CAAA,CAAA;AAAA,cAEhF,EAAC,MAAM,IAAA,CAAK,KAAA,EAAO,WAAW,OAAA,EAAS,YAAA,EAAc,eAAe,IAAA;AAAI,aAC1E;AAAA,UACF;AAEA,UAAA,IAAA,IAAQ,YAAA;AAAA,QACV;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,YAAA,GAAe;AACb,QAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,CAAA,EAAG,CAAC,CAAA;AACjC,QAAA,MAAM,YAAA,GAAA,iBAAe,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,CAAE,OAAA,CAAQ,GAAA,EAAK,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAElF,QAAA,MAAM,gBAAA,GAAmB,KAAK,GAAA,CAAI,QAAA;AAGlC,QAAA,MAAM,eAAe,gBAAA,GACjB;AAAA,UACE,SAAA,EAAW,iBAAiB,SAAA,IAAa,KAAA;AAAA,UACzC,UAAA,EAAY,gBAAA,CAAiB,UAAA,IAAcG,OAAAA,CAAO,UAAA,EAAW;AAAA,UAC7D,aAAA,EAAe,iBAAiB,aAAA,IAAiB,YAAA;AAAA,UACjD,mBAAA,EAAqB,iBAAiB,mBAAA,IAAuB,EAAA;AAAA,UAC7D,iBAAA,EAAmB,iBAAiB,iBAAA,IAAqB,EAAA;AAAA,UACzD,cAAA,EAAgB,iBAAiB,cAAA,IAAkB,EAAA;AAAA,UACnD,YAAA,EAAc,iBAAiB,YAAA,IAAgB,EAAA;AAAA,UAC/C,SAAA,EAAW,gBAAA,CAAiB,SAAA,IAAaF,KAAAA,CAAK,QAAA,CAAS,IAAA,CAAK,KAAA,EAAOA,KAAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,UAC3F,WAAA,EAAa,iBAAiB,WAAA,IAAe,EAAA;AAAA,UAC7C,OAAA,EAAS,iBAAiB,OAAA,IAAW,EAAA;AAAA,UACrC,cAAA,EAAgB,iBAAiB,cAAA,IAAkB,EAAA;AAAA,UACnD,SAAA,EAAW,iBAAiB,SAAA,IAAa,EAAA;AAAA,UACzC,aAAA,EAAe,iBAAiB,aAAA,IAAiB,EAAA;AAAA,UACjD,OAAA,EAAS,iBAAiB,OAAA,IAAW;AAAA,YACnC,WAAA,EAAa;AAAA,cACX,aAAA,EAAe,SAAA;AAAA,cACf,SAAA,EAAW;AAAA;AACb;AACF,SACF,GACA;AAAA,UACE,SAAA,EAAW,KAAA;AAAA,UACX,UAAA,EAAYE,QAAO,UAAA,EAAW;AAAA,UAC9B,aAAA,EAAe,YAAA;AAAA,UACf,mBAAA,EAAqB,EAAA;AAAA,UACrB,iBAAA,EAAmB,EAAA;AAAA,UACnB,cAAA,EAAgB,EAAA;AAAA,UAChB,YAAA,EAAc,EAAA;AAAA,UACd,SAAA,EAAWF,MAAK,QAAA,CAAS,IAAA,CAAK,OAAOA,KAAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,UAC7D,WAAA,EAAa,EAAA;AAAA,UACb,OAAA,EAAS,EAAA;AAAA,UACT,cAAA,EAAgB,EAAA;AAAA,UAChB,SAAA,EAAW,EAAA;AAAA,UACX,aAAA,EAAe,EAAA;AAAA,UACf,OAAA,EAAS;AAAA,YACP,WAAA,EAAa;AAAA,cACX,aAAA,EAAe,SAAA;AAAA,cACf,SAAA,EAAW;AAAA;AACb;AACF,SACF;AAIJ,QAAA,IAAI,iBAAiB,EAAC;AACtB,QAAA,IAAI,gBAAA,IAAoB,gBAAA,CAAiB,MAAA,IAAU,gBAAA,CAAiB,OAAO,cAAA,EAAgB;AACzF,UAAA,cAAA,GAAiB,KAAA,CAAM,OAAA,CAAQ,gBAAA,CAAiB,MAAA,CAAO,cAAc,CAAA,GACjE,gBAAA,CAAiB,MAAA,CAAO,cAAA,GACxB,CAAC,gBAAA,CAAiB,MAAA,CAAO,cAAc,CAAA;AAAA,QAC7C;AAEA,QAAA,MAAM,SAAA,GAAY;AAAA,UAChB,cAAA,EAAgB;AAAA,YACd,GAAG,YAAA;AAAA,YACH,MAAA,EAAQ;AAAA,cACN,gBAAgB,IAAA,CAAK,GAAA,CAAI,QAAQ,GAAA,CAAI,CAAoB,QAA8B,KAAA,KAAU;AAE/F,gBAAA,MAAM,gBAAgB,cAAA,CAAe,IAAA,CAAK,CAAoB,CAAA,KAAM,CAAA,CAAE,cAAc,MAAM,CAAA;AAE1F,gBAAA,OAAO;AAAA,kBACL,SAAA,EAAW,MAAA;AAAA,kBACX,SAAA,EAAW,IAAA,CAAK,mBAAA,GAAsB,KAAK,EAAE,CAAC,CAAA;AAAA,kBAC9C,QAAA,EAAU,IAAA,CAAK,mBAAA,GAAsB,KAAK,EAAE,CAAC,CAAA;AAAA,kBAC7C,IAAA,EAAM,IAAA,CAAK,mBAAA,GAAsB,KAAK,EAAE,CAAC,CAAA;AAAA,kBACzC,WAAA,EAAa,IAAA,CAAK,aAAA,GAAgB,KAAK,CAAA;AAAA,kBACvC,MAAA,EAAQ,IAAA,CAAK,oBAAA,GAAuB,KAAK,EAAE,CAAC,CAAA;AAAA,kBAC5C,MAAA,EAAQ,IAAA,CAAK,oBAAA,GAAuB,KAAK,EAAE,CAAC,CAAA;AAAA,kBAC5C,OAAA,EAAS,eAAe,OAAA,IAAW,EAAA;AAAA,kBACnC,cAAc,6BAAA,CAA8B,aAAA,EAAe,cAAc,IAAA,CAAK,YAAA,GAAe,KAAK,CAAC,CAAA;AAAA,kBACnG,MAAM,qBAAA,CAAsB,aAAA,EAAe,MAAM,IAAA,CAAK,YAAA,GAAe,KAAK,CAAC;AAAA,iBAC7E;AAAA,cACF,CAAC;AAAA,aACH;AAAA,YACA,aAAa,IAAA,CAAK,YAAA;AAAA,YAClB,gBAAgB,IAAA,CAAK,eAAA;AAAA,YACrB,MAAA,EACE,IAAA,CAAK,oBAAA,IAAwB,IAAA,CAAK,oBAAA,CAAqB,SAAS,CAAA,GAC5D,IAAA,CAAK,oBAAA,CAAqB,IAAA,CAAK,oBAAA,CAAqB,MAAA,GAAS,CAAC,CAAA,CAAE,CAAC,CAAA,GACjE,IAAA,CAAK,oBAAA,CAAqB,IAAA,CAAK,qBAAqB,MAAA,GAAS,CAAC,CAAA,CAAE,CAAC,CAAA,GACjE,CAAA;AAAA,YACN,MAAA,EAAQ,KAAK,YAAA,EAAc;AAAA;AAC7B,SACF;AAIA,QAAA,MAAM,EAAC,MAAA,EAAQ,GAAG,KAAA,KAAS,SAAA,CAAU,cAAA;AAErC,QAAA,KAAA,MAAW,CAAC,QAAA,EAAU,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AACrD,UAAA,gBAAA,CAAiB,KAAA,EAAO,UAAU,WAAA,EAAa,EAAC,MAAM,IAAA,CAAK,KAAA,EAAO,KAAA,EAAO,aAAA,EAAc,CAAA;AAAA,QACzF;AAEA,QAAA,KAAA,MAAW,EAAC,SAAA,EAAW,GAAG,KAAA,EAAK,IAAK,OAAO,cAAA,EAAgB;AACzD,UAAA,KAAA,MAAW,CAAC,QAAA,EAAU,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AACrD,YAAA,gBAAA,CAAiB,KAAA,EAAO,QAAA,EAAU,CAAA,OAAA,EAAU,SAAS,CAAA,CAAA,CAAA,EAAK;AAAA,cACxD,MAAA,EAAQ,SAAA;AAAA,cACR,MAAM,IAAA,CAAK,KAAA;AAAA,cACX,KAAA,EAAO;AAAA,aACR,CAAA;AAAA,UACH;AAAA,QACF;AAEA,QAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,OAAA,CAAQ;AAAA,UAC9B,UAAA,EAAY;AAAA,YACV,MAAA,EAAQ,IAAA;AAAA,YACR,OAAA,EAAS,MAAA;AAAA,YACT,MAAA,EAAQ;AAAA;AACV,SACD,CAAA;AACD,QAAA,IAAA,CAAK,OAAA,GAAU,OAAA,CAAQ,WAAA,CAAY,SAAS,CAAA,GAAI,MAAA;AAChD,QAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,CAAA,EAAG,CAAC,CAAA;AAAA,MACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA6CA,iBAAA,GAAoB;AAClB,QAAA,IAAA,CAAK,gBAAgB,EAAC;AACtB,QAAA,IAAA,CAAK,eAAe,EAAC;AACrB,QAAA,IAAA,CAAK,uBAAuB,EAAC;AAC7B,QAAA,IAAA,CAAK,sBAAsB,EAAC;AAK5B,QAAA,IAAI,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AACjC,UAAA,MAAM,IAAI,mBAAmB,yCAAA,EAA2C;AAAA,YACtE,MAAM,IAAA,CAAK,KAAA;AAAA,YACX,KAAA,EAAO;AAAA,WACR,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,OAAA,GAAU,KAAK,GAAA,CAAI,OAAA;AACzB,QAAA,MAAM,IAAA,GAAO,KAAK,GAAA,CAAI,IAAA;AACtB,QAAA,MAAM,aAAa,OAAA,CAAQ,MAAA;AAC3B,QAAA,MAAM,UAAU,IAAA,CAAK,MAAA;AAErB,QAAA,mBAAA,CAAoB,OAAA,EAAS,KAAK,KAAK,CAAA;AAIvC,QAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,aAAa,CAAA;AAE5D,QAAA,IAAA,CAAK,aAAA,CAAc,cAAA,EAAgB,CAAA,EAAG,UAAU,CAAA;AAWhD,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,CAAuB,IAAA,KAAS;AACxD,UAAA,MAAM,KAAA,GAAQ,MAAA,KAAW,IAAA,GAAO,IAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,SAAA,KAAc,SAAA,CAAU,KAAA,KAAU,IAAI,CAAA,IAAK,IAAA;AAEhG,UAAA,MAAM,KAAA,uBAAY,GAAA,EAAI;AAEtB,UAAA,IAAI,OAAA,GAAU,IAAA;AAEd,UAAA,IAAI,YAAA,GAAe,IAAA;AAEnB,UAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,gBAAA,CAAiB,KAAK,CAAA,EAAG;AAC7C,YAAA,YAAA,GAAe,iBAAiB,KAAK,CAAA;AAAA,UACvC,CAAA,MAAA,IAAW,UAAU,IAAA,EAAM;AACzB,YAAA,OAAA,uBAAc,GAAA,EAAI;AAIlB,YAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,KAAA,CAAM,MAAA,CAAO,QAAQ,KAAA,EAAA,EAAS;AACxD,cAAA,MAAM,QAAQ,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAE7C,cAAA,IAAI,UAAU,MAAA,EAAW;AACvB,gBAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,MAAA,CAAO,KAAK,GAAG,KAAK,CAAA;AAAA,cACxC,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,EAAU;AACpC,gBAAA,OAAA,CAAQ,GAAA,CAAI,MAAM,MAAA,CAAO,KAAK,GAAG,CAAC,KAAA,EAAO,KAAK,CAAC,CAAA;AAAA,cACjD,CAAA,MAAO;AACL,gBAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,cAClB;AAAA,YACF;AAAA,UACF;AAEA,UAAA,OAAO;AAAA,YACL,IAAA;AAAA,YACA,MAAM,EAAC;AAAA,YACP,OAAO,EAAC;AAAA,YACR,KAAA;AAAA;AAAA;AAAA,YAGA,QAAQ,KAAA,KAAU,IAAA,IAAQ,iBAAiB,IAAA,GAAO,KAAA,uBAAY,GAAA,EAAI;AAAA,YAClE,QAAA,sBAAc,GAAA,EAAI;AAAA,YAClB,KAAA;AAAA,YACA,YAAA;AAAA,YACA,OAAA;AAAA,YACA,OAAO,EAAC,SAAA,EAAW,OAAO,YAAA,EAAc,KAAA,EAAO,aAAa,KAAA;AAAK,WACnE;AAAA,QACF,CAAC,CAAA;AAKD,QAAA,MAAM,UAAU,KAAA,CAAM,GAAA,CAAI,CAAC,MAAA,KAAW,OAAO,MAAM,CAAA;AACnD,QAAA,MAAM,YAAY,KAAA,CAAM,GAAA,CAAI,CAAC,MAAA,KAAW,OAAO,QAAQ,CAAA;AAEvD,QAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,GAAA,CAAI,MAAM,KAAK,CAAA;AAI5C,QAAA,MAAM,IAAA,GAAO,IAAI,QAAA,EAAS;AAE1B,QAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,MAAM,YAAY,CAAA;AAC3C,QAAA,MAAM,cAAA,GAAiB,kBAAkB,OAAO,CAAA;AAKhD,QAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,MAAM,IAAI,CAAA;AAQtC,QAAA,KAAA,IAAS,GAAA,GAAM,CAAA,EAAG,GAAA,GAAM,OAAA,EAAS,GAAA,EAAA,EAAO;AACtC,UAAA,IAAK,MAAM,WAAA,KAAgB,CAAA,IAAK,GAAA,KAAQ,CAAA,IAAM,QAAQ,cAAA,EAAgB;AACpE,YAAA,SAAA,CAAU,IAAA,EAAM,KAAK,OAAO,CAAA;AAAA,UAC9B;AAEA,UAAA,MAAM,MAAA,GAAS,KAAK,GAAG,CAAA;AAMvB,UAAA,IAAI,MAAA,KAAW,QAAQ,MAAA,KAAW,MAAA,IAAa,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AACrE,YAAA,MAAM,IAAI,mBAAmB,qCAAA,EAAuC;AAAA,cAClE,GAAA;AAAA,cACA,MAAM,OAAO,MAAA;AAAA,cACb,MAAM,IAAA,CAAK,KAAA;AAAA,cACX,KAAA,EAAO;AAAA,aACR,CAAA;AAAA,UACH;AAKA,UAAA,IAAI,WAAW,IAAA,IAAQ,MAAA,KAAW,MAAA,IAAa,MAAA,CAAO,SAAS,UAAA,EAAY;AACzE,YAAA,MAAM,IAAI,mBAAmB,CAAA,IAAA,EAAO,GAAG,QAAQ,MAAA,CAAO,MAAM,CAAA,sBAAA,EAAyB,UAAU,CAAA,OAAA,CAAA,EAAW;AAAA,cACxG,GAAA;AAAA,cACA,QAAQ,MAAA,CAAO,MAAA;AAAA,cACf,MAAA,EAAQ,UAAA;AAAA,cACR,MAAM,IAAA,CAAK,KAAA;AAAA,cACX,KAAA,EAAO;AAAA,aACR,CAAA;AAAA,UACH;AAEA,UAAA,KAAA,IAAS,MAAA,GAAS,CAAA,EAAG,MAAA,GAAS,UAAA,EAAY,MAAA,EAAA,EAAU;AAClD,YAAA,MAAM,KAAA,GAAQ,SAAS,MAAM,CAAA;AAE7B,YAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW;AACzC,cAAA,YAAA,CAAa,MAAM,CAAA,GAAI,IAAA;AACvB,cAAA;AAAA,YACF;AAIA,YAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,cAAA,IAAI,CAAC,SAAA,CAAU,MAAM,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA,EAAG;AACjC,gBAAA,aAAA,CAAc,MAAM,MAAM,CAAA,EAAG,KAAA,EAAO,GAAA,EAAK,KAAK,KAAK,CAAA;AAAA,cACrD;AAEA,cAAA;AAAA,YACF;AAGA,YAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,YAAA,IAAI,IAAA,GAAO,CAAA;AAEX,YAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,cAAA,KAAA,GAAQ,KAAK,MAAM,CAAA;AAEnB,cAAA,IAAI,UAAU,IAAA,EAAM;AAClB,gBAAA,KAAA,CAAM,KAAA,EAAA;AACN,gBAAA,IAAA,GAAO,MAAA,CAAO,KAAA,EAAO,KAAA,CAAM,IAAI,CAAA;AAE/B,gBAAA,IAAI,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,KAAM,KAAA,EAAO;AAChC,kBAAA;AAAA,gBACF;AAEA,gBAAA,KAAA,CAAM,MAAA,EAAA;AAGN,gBAAA,IAAI,UAAU,YAAA,EAAc;AAC1B,kBAAA,KAAA,GAAQ,eAAA,CAAgB,SAAS,IAAI,CAAA;AACrC,kBAAA,IAAA,CAAK,MAAM,CAAA,GAAI,KAAA;AAEf,kBAAA,IAAI,UAAU,IAAA,EAAM;AAClB,oBAAA,OAAA,CAAQ,MAAM,CAAA,GAAI,EAAC,GAAA,EAAK,OAAO,CAAA,EAAC;AAAA,kBAClC,CAAA,MAAO;AACL,oBAAA,KAAA,CAAM,KAAA,GAAQ,CAAA;AACd,oBAAA,KAAA,CAAM,MAAA,GAAS,CAAA;AACf,oBAAA,IAAA,GAAO,MAAA,CAAO,KAAA,EAAO,KAAA,CAAM,IAAI,CAAA;AAAA,kBACjC;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAGA,YAAA,IAAI,OAAA,CAAQ,MAAM,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA,EAAG;AAC9B,cAAA,IAAI,UAAU,IAAA,EAAM;AAClB,gBAAA,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,GAAI,KAAA;AAAA,cACvB;AAEA,cAAA;AAAA,YACF;AAKA,YAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,cAAA,IAAI,aAAA,CAAc,KAAK,CAAA,KAAM,IAAA,EAAM;AACjC,gBAAA,WAAA,CAAY,KAAA,EAAO,IAAA,EAAM,EAAC,MAAA,EAAQ,OAAA,CAAQ,MAAM,CAAA,EAAG,GAAA,EAAK,IAAA,EAAM,IAAA,CAAK,KAAA,EAAO,KAAA,EAAO,oBAAmB,CAAA;AAAA,cACtG;AAAA,YACF,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,EAAU;AACpC,cAAA,IAAI,WAAA,CAAY,KAAK,CAAA,KAAM,IAAA,EAAM;AAC/B,gBAAA,SAAA,CAAU,OAAO,gBAAA,EAAkB;AAAA,kBACjC,MAAA,EAAQ,QAAQ,MAAM,CAAA;AAAA,kBACtB,GAAA;AAAA,kBACA,MAAM,IAAA,CAAK,KAAA;AAAA,kBACX,KAAA,EAAO;AAAA,iBACR,CAAA;AAAA,cACH;AAAA,YACF,CAAA,MAAO;AACL,cAAA,UAAA,CAAW,OAAO,OAAA,CAAQ,MAAM,CAAA,EAAG,GAAA,EAAK,KAAK,KAAK,CAAA;AAAA,YACpD;AAEA,YAAA,OAAA,CAAQ,MAAM,CAAA,CAAE,GAAA,CAAI,KAAA,EAAO,WAAA,CAAY,KAAA,CAAM,MAAM,CAAA,EAAG,KAAA,EAAO,GAAA,EAAK,IAAA,CAAK,KAAK,CAAC,CAAA;AAG7E,YAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,EAAU;AAC/C,cAAA,IAAA,CAAK,MAAM,CAAA,GAAI,KAAA,CAAM,QAAA,CAAS,MAAM,KAAK,CAAA;AAAA,YAC3C;AAAA,UACF;AAAA,QACF;AAOA,QAAA,MAAM,gBAAgB,EAAC;AACvB,QAAA,IAAI,aAAA,GAAgB,CAAA;AAEpB,QAAA,KAAA,IAAS,MAAA,GAAS,CAAA,EAAG,MAAA,GAAS,UAAA,EAAY,MAAA,EAAA,EAAU;AAClD,UAAA,MAAM,EAAC,IAAA,EAAM,KAAA,EAAK,GAAI,MAAM,MAAM,CAAA;AAClC,UAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,IAAA,CAAK,MAAM,CAAA;AACxC,UAAA,IAAI,UAAA,GAAa,CAAA;AAGjB,UAAA,IAAI,UAAA,GAAa,CAAA;AAEjB,UAAA,KAAA,IAAS,IAAA,GAAO,CAAA,EAAG,IAAA,GAAO,IAAA,CAAK,QAAQ,IAAA,EAAA,EAAQ;AAC7C,YAAA,MAAM,GAAA,GAAM,KAAK,IAAI,CAAA;AACrB,YAAA,MAAM,IAAA,GAAO,MAAM,IAAI,CAAA;AAEvB,YAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,cAAA,UAAA,EAAA;AAMA,cAAA,IAAI,aAAA,CAAc,GAAG,CAAA,KAAM,IAAA,EAAM;AAC/B,gBAAA,WAAA,CAAY,GAAA,EAAK,IAAA,EAAM,EAAC,MAAA,EAAQ,OAAA,CAAQ,MAAM,CAAA,EAAG,IAAA,EAAM,IAAA,CAAK,KAAA,EAAO,KAAA,EAAO,kBAAA,EAAmB,CAAA;AAAA,cAC/F;AAEA,cAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,WAAA,CAAY,IAAI,MAAM,IAAA,EAAM;AAC/C,gBAAA,SAAA,CAAU,MAAM,0BAAA,EAA4B;AAAA,kBAC1C,MAAA,EAAQ,QAAQ,MAAM,CAAA;AAAA,kBACtB,MAAM,IAAA,CAAK,KAAA;AAAA,kBACX,KAAA,EAAO;AAAA,iBACR,CAAA;AAAA,cACH;AAEA,cAAA,KAAA,CAAM,IAAI,CAAA,GAAI,MAAA,CAAO,GAAA,EAAK,IAAI,CAAA;AAC9B,cAAA,UAAA,IAAc,gBAAA,CAAiB,KAAA,CAAM,IAAI,CAAA,EAAG,KAAK,IAAI,CAAA;AAAA,YACvD,CAAA,MAAO;AACL,cAAA,KAAA,CAAM,IAAI,CAAA,GAAI,MAAA,CAAO,IAAA,EAAM,GAAG,CAAA;AAC9B,cAAA,UAAA,IAAc,gBAAA,CAAiB,KAAA,CAAM,IAAI,CAAA,EAAG,MAAM,GAAG,CAAA;AAAA,YACvD;AAAA,UACF;AAIA,UAAA,MAAM,YAAA,GAAe,MAAA,CAAO,WAAA,CAAY,UAAU,CAAA;AAClD,UAAA,IAAI,MAAA,GAAS,CAAA;AAEb,UAAA,KAAA,IAAS,IAAA,GAAO,CAAA,EAAG,IAAA,GAAO,IAAA,CAAK,QAAQ,IAAA,EAAA,EAAQ;AAC7C,YAAA,MAAM,GAAA,GAAM,KAAK,IAAI,CAAA;AAErB,YAAA,MAAA,GACE,OAAO,QAAQ,QAAA,GACX,WAAA,CAAY,cAAc,MAAA,EAAQ,KAAA,CAAM,IAAI,CAAA,EAAG,GAAA,EAAK,MAAM,IAAI,CAAC,IAC/D,WAAA,CAAY,YAAA,EAAc,QAAQ,KAAA,CAAM,IAAI,CAAA,EAAG,IAAA,EAAM,GAAG,CAAA;AAAA,UAChE;AAEA,UAAAC,OAAAA,CAAO,MAAA,KAAW,UAAA,EAAY,8EAA8E,CAAA;AAE5G,UAAA,aAAA,CAAc,KAAK,YAAY,CAAA;AAC/B,UAAA,IAAA,CAAK,oBAAA,EAAsB,KAAK,CAAC,aAAA,EAAe,YAAY,YAAA,CAAa,MAAM,CAAC,CAAC,CAAA;AACjF,UAAA,IAAA,CAAK,aAAA,EAAe,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA;AACpC,UAAA,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,KAAA,CAAM,MAAM,EAAE,KAAK,CAAA;AAC3C,UAAA,MAAM,OAAA,GAAU,KAAA,CAAM,MAAM,CAAA,CAAE,WAAW,KAAA,CAAM,MAAM,CAAA,CAAE,KAAA,GAAQ,UAAA,GAAa,SAAA,CAAU,KAAA,CAAM,MAAM,EAAE,MAAM,CAAA;AAC1G,UAAA,MAAM,KAAA,GAAQ,KAAK,MAAM,CAAA;AAEzB,UAAA,IAAA,CAAK,qBAAqB,IAAA,CAAK;AAAA,YAC7B,MAAA,EAAQ,KAAA,CAAM,MAAM,CAAA,CAAE,MAAA;AAAA,YACtB,KAAA,EAAO,KAAA,CAAM,MAAM,CAAA,CAAE,KAAA;AAAA,YACrB,QAAA,EAAU,KAAA,CAAM,MAAM,CAAA,CAAE,QAAA;AAAA,YACxB,OAAA;AAAA,YACA,OACE,KAAA,KAAU,YAAA,GACN,IACA,KAAA,KAAU,IAAA,GACR,MAAM,KAAA,GACN,iBAAA;AAAA,cAAkB,IAAA;AAAA,cAAM,MAAA;AAAA;AAAA,cAAqD,QAAQ,MAAM,CAAA;AAAA,cAAI;AAAA;AAAO,WAC/G,CAAA;AAED,UAAA,aAAA,IAAiB,UAAA;AAEjB,UAAA,IAAA,CAAK,aAAA,CAAc,cAAA,EAAgB,MAAA,GAAS,CAAA,EAAG,UAAU,CAAA;AAAA,QAC3D;AAGA,QAAA,IAAA,CAAK,aAAA,GAAgB,MAAA,CAAO,MAAA,CAAO,aAAa,CAAA;AAAA,MAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAyBA,gBAAA,GAAmB;AACjB,QAAAA,OAAAA,CAAO,IAAA,CAAK,aAAA,EAAe,+CAA+C,CAAA;AAC1E,QAAAA,OAAAA,CAAO,IAAA,CAAK,oBAAA,EAAsB,wDAAwD,CAAA;AAC1F,QAAAA,OAAAA,CAAO,IAAA,CAAK,mBAAA,EAAqB,+CAA+C,CAAA;AAEhF,QAAA,IAAA,CAAK,sBAAsB,EAAC;AAE5B,QAAA,MAAM,OAAA,GAAU,KAAK,GAAA,CAAI,OAAA;AACzB,QAAA,MAAM,IAAA,GAAO,KAAK,GAAA,CAAI,IAAA;AACtB,QAAA,MAAM,UAAU,IAAA,CAAK,MAAA;AACrB,QAAA,MAAM,aAAa,OAAA,CAAQ,MAAA;AAE3B,QAAA,IAAA,CAAK,YAAA,GAAe,OAAA;AACpB,QAAA,IAAA,CAAK,aAAA,CAAc,aAAA,EAAe,CAAA,EAAG,OAAO,CAAA;AAK5C,QAAA,MAAM,SAAS,EAAC;AAEhB,QAAA,IAAI,SAAA,GAAY,CAAA;AAEhB,QAAA,KAAA,IAAS,MAAA,GAAS,CAAA,EAAG,MAAA,GAAS,UAAA,EAAY,MAAA,EAAA,EAAU;AAClD,UAAA,MAAM,iBAAA,GAAoB,IAAA,CAAK,oBAAA,CAAqB,MAAM,EAAE,CAAC,CAAA;AAC7D,UAAA,MAAM,WAAA,GAAc,IAAA,CAAK,aAAA,CAAc,MAAM,CAAA;AAC7C,UAAA,MAAM,SAAA,GAAY,oBAAoB,CAAA,GAAI,CAAA;AAQ1C,UAAA,MAAM,cAAA,GAAiB,WAAA,KAAgB,CAAA,GAAI,CAAA,GAAI,cAAc,CAAA,GAAI,SAAA;AAGjE,UAAA,MAAM,WAAW,cAAA,KAAmB,CAAA,GAAI,IAAI,EAAA,GAAK,IAAA,CAAK,MAAM,cAAc,CAAA;AAU1E,UAAA,MAAM,MAAA,GAAS,IAAA,CAAK,mBAAA,CAAoB,MAAM,CAAA;AAC9C,UAAA,MAAM,OACJ,MAAA,CAAO,MAAA,KAAW,MAAA,CAAO,KAAA,GACrB,CAAC,MAAA,CAAO,KAAA,EAAO,MAAA,CAAO,QAAQ,IAC9B,CAAC,MAAA,CAAO,QAAQ,MAAA,CAAO,KAAA,EAAO,OAAO,QAAQ,CAAA;AAEnD,UAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,YAAA,KAAA,MAAW,KAAA,IAAS,GAAA,CAAI,MAAA,EAAO,EAAG;AAChC,cAAA,IAAI,KAAA,GAAQ,YAAY,cAAA,EAAgB;AACtC,gBAAA,MAAM,IAAI,mBAAmB,sDAAA,EAAwD;AAAA,kBACnF,KAAA,EAAO,QAAQ,MAAM,CAAA;AAAA,kBACrB,aAAa,KAAA,GAAQ,SAAA;AAAA,kBACrB,cAAA;AAAA,kBACA,WAAA;AAAA,kBACA,MAAM,IAAA,CAAK,KAAA;AAAA,kBACX,KAAA,EAAO;AAAA,iBACR,CAAA;AAAA,cACH;AAAA,YACF;AAAA,UACF;AAEA,UAAA,MAAA,CAAO,IAAA,CAAK,EAAC,QAAA,EAAU,aAAA,CAAc,WAAW,QAAQ,CAAA,EAAG,WAAU,CAAA;AAErE,UAAA,IAAA,CAAK,mBAAA,CAAoB,KAAK,CAAC,SAAA,EAAW,UAAU,iBAAA,GAAoB,EAAA,GAAK,CAAC,CAAC,CAAA;AAE/E,UAAA,SAAA,IAAa,QAAA;AAAA,QACf;AAKA,QAAA,MAAM,cAAA,GAAiB,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,IAAA,CAAK,SAAA,GAAY,CAAC,CAAC,CAAA;AAE3D,QAAA,IAAA,CAAK,eAAA,GAAkB,cAAA;AACvB,QAAA,IAAA,CAAK,YAAA,GAAe,MAAA,CAAO,KAAA,CAAM,OAAA,GAAU,cAAc,CAAA;AAEzD,QAAA,MAAM,gBAAA,GAAmB,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,OAAA,GAAU,GAAG,CAAC,CAAA;AAI9D,QAAA,MAAM,UAAU,IAAA,CAAK,mBAAA,CAAoB,IAAI,CAAC,MAAA,KAAW,OAAO,MAAM,CAAA;AACtE,QAAA,MAAM,SAAS,IAAA,CAAK,mBAAA,CAAoB,IAAI,CAAC,MAAA,KAAW,OAAO,KAAK,CAAA;AACpE,QAAA,MAAM,YAAY,IAAA,CAAK,mBAAA,CAAoB,IAAI,CAAC,MAAA,KAAW,OAAO,QAAQ,CAAA;AAI1E,QAAA,MAAM,eAAe,IAAA,CAAK,aAAA;AAC1B,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,mBAAA,CAAoB,GAAA,CAAI,CAAC,MAAA,KAAW,cAAA,CAAe,MAAA,CAAO,OAAA,EAAS,MAAA,CAAO,KAAK,CAAC,CAAA;AACpG,QAAA,MAAM,QAAQ,OAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,OAAO,EAAE,MAAM,CAAA;AACnD,QAAA,MAAM,IAAA,GAAO,IAAI,QAAA,EAAS;AAC1B,QAAA,MAAM,IAAA,GAAO,KAAK,mBAAA,CAAoB,GAAA;AAAA,UAAI,CAAC,MAAA,EAAQ,MAAA,KACjD,MAAA,CAAO,MAAM,IAAI,cAAA,CAAe,MAAA,CAAO,OAAA,EAAS,MAAA,CAAO,OAAO,YAAA,CAAa,MAAM,CAAA,EAAG,KAAA,EAAO,IAAI,CAAA,GAAI;AAAA,SACrG;AACA,QAAA,MAAM,cAAA,GAAiB,kBAAkB,OAAO,CAAA;AAEhD,QAAA,KAAA,IAAS,GAAA,GAAM,GAAG,UAAA,GAAa,CAAA,EAAG,MAAM,OAAA,EAAS,GAAA,EAAA,EAAO,cAAc,cAAA,EAAgB;AACpF,UAAA,IAAK,MAAM,WAAA,KAAgB,CAAA,IAAK,GAAA,KAAQ,CAAA,IAAM,QAAQ,cAAA,EAAgB;AACpE,YAAA,SAAA,CAAU,IAAI,CAAA;AAAA,UAChB;AAEA,UAAA,MAAM,MAAA,GAAS,KAAK,GAAG,CAAA;AAEvB,UAAA,KAAA,IAAS,MAAA,GAAS,CAAA,EAAG,MAAA,GAAS,UAAA,EAAY,MAAA,EAAA,EAAU;AAClD,YAAA,MAAM,KAAA,GAAQ,SAAS,MAAM,CAAA;AAE7B,YAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW;AAGzC,cAAA;AAAA,YACF;AAEA,YAAA,MAAM,QAAQ,OAAO,KAAA,KAAU,QAAA,GAAW,IAAA,CAAK,MAAM,CAAA,GAAI,IAAA;AAEzD,YAAA,IAAI,KAAA;AAEJ,YAAA,IAAI,UAAU,IAAA,EAAM;AAElB,cAAA,KAAA,CAAM,KAAA,EAAA;AACN,cAAA,MAAM,IAAA,GAAO,MAAA,CAAO,KAAA,EAAO,KAAA,CAAM,IAAI,CAAA;AAErC,cAAA,IAAI,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,KAAM,KAAA,EAAO;AAChC,gBAAA,KAAA,GAAQ,KAAA,CAAM,QAAQ,IAAI,CAAA;AAAA,cAC5B,CAAA,MAAO;AACL,gBAAA,KAAA,GAAQ,OAAA,CAAQ,MAAM,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA;AAGjC,gBAAA,IAAI,UAAU,MAAA,EAAW;AACvB,kBAAA,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,GAAI,KAAA;AACrB,kBAAA,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,KAAA;AAGtB,kBAAA,IAAI,KAAA,CAAM,SAAA,CAAU,KAAK,CAAA,EAAG;AAC1B,oBAAA,KAAA,CAAM,MAAA,EAAA;AAAA,kBACR;AAAA,gBACF;AAAA,cACF;AAAA,YACF,CAAA,MAAO;AAGL,cAAA,KAAA,GACE,OAAO,UAAU,QAAA,GACZ,SAAA,CAAU,MAAM,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA,IAAK,MAAA,CAAO,MAAM,CAAA,CAAE,GAAA,CAAI,MAAM,MAAM,CAAA,GAChE,QAAQ,MAAM,CAAA,CAAE,IAAI,KAAK,CAAA;AAAA,YACjC;AAMA,YAAA,IAAI,UAAU,MAAA,EAAW;AACvB,cAAA,MAAM,IAAI,mBAAmB,0CAAA,EAA4C;AAAA,gBACvE,KAAA,EAAO,QAAQ,MAAM,CAAA;AAAA,gBACrB,GAAA;AAAA,gBACA,MAAM,IAAA,CAAK,KAAA;AAAA,gBACX,KAAA,EAAO;AAAA,eACR,CAAA;AAAA,YACH;AAEA,YAAA,aAAA,CAAc,IAAA,CAAK,YAAA,EAAc,UAAA,EAAY,MAAA,CAAO,MAAM,CAAA,CAAE,QAAA,EAAU,KAAA,GAAQ,MAAA,CAAO,MAAM,CAAA,CAAE,SAAS,CAAA;AAAA,UACxG;AAGA,UAAA,IAAA,CAAK,MAAM,CAAA,IAAK,gBAAA,KAAqB,CAAA,IAAK,GAAA,GAAM,MAAM,OAAA,EAAS;AAC7D,YAAA,IAAA,CAAK,aAAA,CAAc,aAAA,EAAe,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA;AAAA,UACpD;AAAA,QACF;AAKA,QAAA,IAAA,CAAK,mBAAA,GAAsB,IAAA;AAAA,MAC7B;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,IAAA,GAAO;AACX,QAAA,IAAA,CAAK,iBAAA,EAAkB;AACvB,QAAA,IAAA,CAAK,gBAAA,EAAiB;AACtB,QAAA,IAAA,CAAK,YAAA,EAAa;AAClB,QAAA,MAAM,KAAK,UAAA,EAAW;AAAA,MACxB;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;AC7wDO,SAAS,YAAA,GAAe;AAC7B,EAAA,OAAO,EAAA,CAAG,mBAAkB,CAAE,eAAA;AAChC;AAYA,SAAS,qBAAA,GAAwB;AAC/B,EAAA,OAAO,CAAC,OAAA,CAAQ,QAAA,CAAS,GAAA,IAAO,CAAC,QAAQ,QAAA,CAAS,IAAA;AACpD;AA6BO,SAAS,eAAA,GAAkB;AAEhC,EAAA,MAAM,aAAa,EAAC;AAEpB,EAAA,IAAI,uBAAsB,EAAG;AAC3B,IAAA,UAAA,CAAW,KAAK,EAAC,MAAA,EAAQ,iBAAiB,KAAA,EAAO,mBAAA,IAAsB,CAAA;AAAA,EACzE;AAKA,EAAA,MAAM,cAAc,OAAO,OAAA,CAAQ,sBAAsB,UAAA,GAAa,OAAA,CAAQ,mBAAkB,GAAI,CAAA;AACpG,EAAA,IAAI,WAAA,GAAc,CAAA,IAAK,WAAA,GAAc,EAAA,CAAG,UAAS,EAAG;AAClD,IAAA,UAAA,CAAW,KAAK,EAAC,MAAA,EAAQ,wBAAA,EAA0B,KAAA,EAAO,aAAY,CAAA;AAAA,EACxE;AAIA,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAC3B,IAAA,UAAA,CAAW,IAAA,CAAK,EAAC,MAAA,EAAQ,qBAAA,EAAuB,OAAO,EAAA,CAAG,QAAA,IAAW,CAAA;AAAA,EACvE;AAGA,EAAA,MAAM,QAAA,GAAW,CAAC,EAAC,MAAA,EAAQ,4BAA4B,KAAA,EAAO,EAAA,CAAG,OAAA,EAAQ,EAAE,CAAA;AAC3E,EAAA,IAAI,OAAO,OAAA,CAAQ,eAAA,KAAoB,UAAA,EAAY;AACjD,IAAA,QAAA,CAAS,IAAA,CAAK,EAAC,MAAA,EAAQ,kBAAA,EAAoB,OAAO,OAAA,CAAQ,eAAA,IAAkB,CAAA;AAAA,EAC9E;AAEA,EAAA,MAAM,OAAA,GAAU,UAAA,CAAW,MAAA,CAAO,CAAC,MAAA,EAAQ,SAAA,KAAe,SAAA,CAAU,KAAA,GAAQ,MAAA,CAAO,KAAA,GAAQ,SAAA,GAAY,MAAO,CAAA;AAE9G,EAAA,OAAO,EAAC,OAAO,OAAA,CAAQ,KAAA,EAAO,WAAW,OAAA,CAAQ,MAAA,EAAQ,YAAY,QAAA,EAAQ;AAC/E;AAwDA,SAAS,mBAAA,GAAsB;AAC7B,EAAA,MAAM,MAAA,GAAS,cAAa,GAAI,8BAAA;AAEhC,EAAA,OAAO,MAAA,GAAS,uBAAuB,MAAA,GAAS,oBAAA;AAClD;AAqFO,SAAS,sBAAA,CAAuB,MAAM,WAAA,EAAa;AACxD,EAAA,IAAI,CAAC,WAAA,IAAe,WAAA,IAAe,KAAK,CAAC,IAAA,IAAQ,QAAQ,CAAA,EAAG;AAC1D,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA,GAAO,cAAc,UAAA,CAAW,iBAAA;AACzC;AAUA,SAAS,iBAAA,CAAkB,MAAM,WAAA,EAAa;AAC5C,EAAA,IAAI,CAAC,WAAA,IAAe,WAAA,IAAe,CAAA,EAAG;AACpC,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,OAAO,UAAA,GAAa,IAAA,IAAQ,cAAA,GAAiB,cAAA,GAAiB,WAAA,CAAA;AAChE;AAEO,SAAS,mBAAA,CACd,eAAA,EACA,OAAA,EACA,SAAA,EACA,WAAA,GAAc,CAAA,EACd,gBAAA,GAAmB,IAAA,EACnB,QAAA,GAAW,IAAA,EACX,YAAA,GAAe,KAAA,EACf;AAEA,EAAA,MAAM,mBAAA,GAAsB,CAAA;AAC5B,EAAA,MAAM,gBAAA,GAAmB,IAAA;AAEzB,EAAA,MAAM,UAAA,GAAa,OAAA,KAAY,IAAA,IAAQ,OAAA,IAAW,YAAY,SAAA,GAAY,OAAA;AAiB1E,EAAA,MAAM,WAAW,QAAA,KAAa,IAAA,GAAO,aAAa,IAAA,CAAK,GAAA,CAAI,UAAU,UAAU,CAAA;AAY/E,EAAA,MAAM,SAAA,GAAY,gBAAA,GAAmB,iBAAA,CAAkB,QAAA,EAAU,WAAW,CAAA,GAAI,UAAA;AAEhF,EAAA,IAAI,OAAA,KAAY,IAAA,IAAQ,OAAA,IAAW,SAAA,IAAa,YAAA,EAAc;AAS5D,IAAA,OAAO,kBAAkB,mBAAA,GAAsB,SAAA;AAAA,EACjD;AAKA,EAAA,MAAM,gBAAgB,OAAA,GAAU,SAAA;AAChC,EAAA,MAAM,gBAAA,GAAmB,IAAA,CAAK,IAAA,CAAK,aAAa,CAAA;AAGhD,EAAA,MAAM,iBAAA,GAAoB,kBAAkB,gBAAA,GAAmB,mBAAA;AAC/D,EAAA,MAAM,oBAAA,GAAuB,eAAA,IAAmB,CAAA,GAAI,gBAAA,CAAA,GAAoB,gBAAA;AAExE,EAAA,OAAO,oBAAoB,oBAAA,GAAuB,SAAA;AACpD;AA0BO,SAAS,kBAAA,CACd,MAAA,EACA,eAAA,EACA,SAAA,EACA,WAAA,EACA,mBAAmB,IAAA,EACnB,eAAA,GAAkB,KAAA,EAClB,YAAA,GAAe,KAAA,EACf;AACA,EAAA,MAAM,MAAA,2BAAgC,IAAA,KACpC,mBAAA,CAAoB,iBAAiB,IAAA,EAAM,SAAA,EAAW,aAAa,gBAAA,EAAkB,IAAA,EAAM,YAAY,CAAA,IACtG,eAAA,GAAkB,uBAAuB,IAAA,CAAK,GAAA,CAAI,MAAM,SAAS,CAAA,EAAG,WAAW,CAAA,GAAI,CAAA,CAAA,EAFvE,QAAA,CAAA;AAIf,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,IAAK,MAAA,EAAQ;AAC/B,IAAA,OAAO,SAAA;AAAA,EACT;AAQA,EAAA,IAAI,MAAA,CAAO,CAAC,CAAA,GAAI,MAAA,EAAQ;AACtB,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,IAAA,GAAO,SAAA;AACX,EAAA,OAAO,IAAA,GAAO,MAAM,CAAA,EAAG;AACrB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAA,CAAO,GAAA,GAAM,QAAQ,CAAC,CAAA;AACvC,IAAA,IAAI,MAAA,CAAO,GAAG,CAAA,IAAK,MAAA,EAAQ;AACzB,MAAA,GAAA,GAAM,GAAA;AAAA,IACR,CAAA,MAAO;AACL,MAAA,IAAA,GAAO,GAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,GAAA;AACT;AA6BO,SAAS,mBAAA,CACd,MAAA,EACA,eAAA,EACA,UAAA,EACA,SAAA,EACA,WAAA,EACA,gBAAA,GAAmB,CAAA,EACnB,eAAA,GAAkB,KAAA,EAClB,YAAA,GAAe,KAAA,EACf;AACA,EAAA,MAAM,OAAA,GAAU,UAAA,KAAe,IAAA,IAAQ,UAAA,IAAc,YAAY,SAAA,GAAY,UAAA;AAE7E,EAAA,MAAM,IAAA,2BAA8B,KAAA,KAAU;AAC5C,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,kBAAkB,OAAO,CAAA;AACvD,IAAA,MAAM,IAAA,GACJ,mBAAA;AAAA,MACE,eAAA;AAAA,MACA,UAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA,IAAA;AAAA,MACA,KAAA,GAAQ,gBAAA;AAAA,MACR;AAAA,KACF,IAAK,eAAA,GAAkB,sBAAA,CAAuB,IAAA,EAAM,WAAW,CAAA,GAAI,CAAA,CAAA;AAErE,IAAA,OAAO,IAAA,IAAQ,MAAA;AAAA,EACjB,CAAA,EAda,MAAA,CAAA;AAgBb,EAAA,IAAI,IAAA,CAAK,OAAO,CAAA,EAAG;AACjB,IAAA,OAAO,OAAA;AAAA,EACT;AAKA,EAAA,IAAI,CAAC,IAAA,CAAK,CAAC,CAAA,EAAG;AACZ,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,IAAA,GAAO,OAAA;AACX,EAAA,OAAO,IAAA,GAAO,MAAM,CAAA,EAAG;AACrB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAA,CAAO,GAAA,GAAM,QAAQ,CAAC,CAAA;AACvC,IAAA,IAAI,IAAA,CAAK,GAAG,CAAA,EAAG;AACb,MAAA,GAAA,GAAM,GAAA;AAAA,IACR,CAAA,MAAO;AACL,MAAA,IAAA,GAAO,GAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,GAAA;AACT;AA6CO,SAAS,0BAAA,CACd,iBACA,OAAA,EACA,SAAA,EACA,UACA,YAAA,GAAe,GAAA,EACf,cAAc,CAAA,EACd,gBAAA,GAAmB,MACnB,IAAA,GAAO,IAAA,EACP,YAAY,IAAA,EACZ,SAAA,GAAY,MACZ,YAAA,GAAe,KAAA,EACf,gBAAgB,CAAA,EAChB;AACA,EAAA,MAAM,SAAS,WAAA,CAAY;AAAA,IACzB,YAAA;AAAA,IACA,aAAA;AAAA,IACA,eAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,gBAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,IAAI,OAAO,IAAA,EAAM;AACf,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,EAAC,OAAA,EAAS,OAAA,EAAO,GAAI,MAAA,CAAO,OAAA;AAMlC,EAAA,MAAM,IAAI,mBAAmB,OAAA,EAAS;AAAA,IACpC,IAAA,EAAM,QAAA;AAAA,IACN,GAAG,OAAA;AAAA,IACH,MAAA,EAAQ,QAAA;AAAA,IACR,KAAA,EAAO,SAAS,MAAM;AAAA,GACvB,CAAA;AACH;AA8CO,SAAS,WAAA,CAAY;AAAA,EAC1B,eAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,GAAe,GAAA;AAAA,EACf,WAAA,GAAc,CAAA;AAAA,EACd,gBAAA,GAAmB,IAAA;AAAA,EACnB,IAAA,GAAO,IAAA;AAAA,EACP,SAAA,GAAY,IAAA;AAAA,EACZ,SAAA,GAAY,IAAA;AAAA,EACZ,QAAA,GAAW,IAAA;AAAA,EACX,YAAA,GAAe,KAAA;AAAA,EACf,aAAA,GAAgB;AAClB,CAAA,EAAG;AACD,EAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,GAAe,CAAA,IAAK,eAAe,CAAA,EAAG;AAC5E,IAAA,MAAM,IAAI,mBAAmB,mDAAA,EAAqD;AAAA,MAChF,YAAA;AAAA,MACA,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,oBAAA;AAAA,MACR,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAaA,EAAA,MAAM,MAAA,GAAS,YAAY,eAAA,EAAgB;AAC3C,EAAA,MAAM,UAAA,GAAa,OAAA,KAAY,IAAA,IAAQ,OAAA,IAAW,YAAY,SAAA,GAAY,OAAA;AAO1E,EAAA,MAAM,QAAA,GAAW,IAAA,KAAS,IAAA,GAAO,IAAA,GAAO,IAAA,CAAK,IAAA;AAC7C,EAAA,MAAM,gBAAA,GAAmB,IAAA,KAAS,IAAA,GAAO,CAAA,GAAI,IAAA,CAAK,QAAA;AAKlD,EAAA,MAAM,WAAW,QAAA,KAAa,IAAA,GAAO,aAAa,IAAA,CAAK,GAAA,CAAI,UAAU,UAAU,CAAA;AAC/E,EAAA,MAAM,UAAA,GAAa,mBAAA;AAAA,IACjB,eAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,gBAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF;AAkBA,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,cAAc,gBAAA,GAAmB,IAAA;AAAA,IACjC,OAAA,EAAS,WAAA;AAAA,IACT,QAAA,EAAU;AAAA,MACR,SAAA,IAAa,WAAA;AACjB,EAAA,MAAM,cAAA,GAAiB,sBAAA,CAAuB,QAAA,EAAU,WAAW,CAAA,GAAI,IAAA;AAQvE,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,UAAA,CAAW,GAAA,CAAI,CAAC,SAAA,KAAc;AACnD,IAAA,MAAM,QAAA,GAAW,UAAU,MAAA,KAAW,eAAA;AAEtC,IAAA,OAAO;AAAA,MACL,GAAG,SAAA;AAAA,MACH,QAAA;AAAA,MACA,KAAA,EAAO,QAAA,GAAW,UAAA,GAAa,UAAA,GAAa,cAAA;AAAA,MAC5C,OAAA,EAAS,UAAU,KAAA,GAAQ,YAAA;AAAA,MAC3B,MAAA,EAAQ,WAAW,aAAA,GAAgB;AAAA,KACrC;AAAA,EACF,CAAC,CAAA;AAQD,EAAA,IAAI,iBAAiB,CAAA,EAAG;AACtB,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,UAAA,CAAW,MAAA,CAAO,CAAC,KAAA,EAAO,SAAA,KAAe,SAAA,CAAU,KAAA,GAAQ,KAAA,CAAM,KAAA,GAAQ,SAAA,GAAY,KAAM,CAAA;AAEjH,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,IAAA;AAAA,MACN,UAAU,EAAC,SAAA,EAAW,UAAA,EAAY,aAAA,EAAe,gBAAgB,SAAA,EAAS;AAAA;AAAA;AAAA;AAAA,MAI1E,MAAA,EAAQ;AAAA,QACN,GAAG,QAAA,CAAS,MAAA,EAAQ,EAAC,GAAG,MAAA,EAAQ,QAAA,EAAU,MAAA,CAAO,MAAA,KAAW,eAAA,EAAe,EAAG,CAAC,CAAA;AAAA,QAC/E,YAAA,EAAc;AAAA,OAChB;AAAA,MACA,OAAO,eAAA,KAAoB,CAAA;AAAA,MAC3B,aAAa;AAAC,KAChB;AAAA,EACF;AAEA,EAAA,MAAM,WAAW,OAAA,CAAQ,MAAA;AAAA,IAAO,CAAC,KAAA,EAAO,SAAA,KACtC,SAAA,CAAU,KAAA,GAAQ,SAAA,CAAU,OAAA,GAAU,KAAA,CAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,SAAA,GAAY;AAAA,GAClF;AACA,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,KAAA,GAAQ,QAAA,CAAS,UAAU,QAAA,GAAW,IAAA;AAE/D,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,eAAA,GAAkB,OAAA,GAAU,OAAA,CAAQ,KAAA,GAAQ,MAAA,CAAO,KAAA;AACzD,EAAA,MAAM,eAAA,GAAkB,OAAA,GAAU,OAAA,CAAQ,KAAA,GAAQ,UAAA;AAClD,EAAA,MAAM,gBAAA,GAAmB,OAAA,GAAU,OAAA,CAAQ,OAAA,GAAU,OAAO,KAAA,GAAQ,YAAA;AAUpE,EAAA,MAAM,uBAAuB,MAAM;AACjC,IAAA,IAAI,OAAA,KAAY,IAAA,IAAQ,aAAA,IAAiB,CAAA,EAAG;AAC1C,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,SAAA,GAAY,mBAAA;AAAA,MAChB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,eAAA,GAAkB,aAAa,CAAA;AAAA,MAC3C,OAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA,gBAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KACF;AAKA,IAAA,MAAM,aAAA,GAAgB,sBAAA,CAAuB,QAAA,EAAU,WAAW,KAAK,gBAAA,IAAoB,IAAA,CAAA;AAM3F,IAAA,OAAO,MAAA,CAAO,UAAA,CAAW,KAAA,CAAM,CAAC,SAAA,KAAc;AAC5C,MAAA,MAAM,QAAA,GAAW,UAAU,MAAA,KAAW,eAAA;AAEtC,MAAA,OAAA,CAAQ,QAAA,GAAW,SAAA,GAAY,SAAA,GAAY,aAAA,KAAkB,UAAU,KAAA,GAAQ,YAAA;AAAA,IACjF,CAAC,CAAA;AAAA,EACH,CAAA,GAAG;AAEH,EAAA,IAAI,OAAA,EAAS;AAOX,IAAA,MAAM,eAAA,GAAkB,CAAC,OAAA,CAAQ,QAAA;AAkBjC,IAAA,MAAM,cAAA,2BAAwC,IAAA,KAAS,gBAAA,IAAoB,kBAAkB,WAAA,CAAY,IAAI,IAAI,CAAA,CAAA,EAA1F,gBAAA,CAAA;AACvB,IAAA,MAAM,OAAA,2BAAiC,IAAA,KACrC,kBAAA;AAAA,MACE,eAAe,IAAI,CAAA;AAAA,MACnB,eAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA,gBAAA;AAAA,MACA,eAAA;AAAA,MACA;AAAA,KACF,EATc,SAAA,CAAA;AAUhB,IAAA,MAAM,UAAA,GAAa,QAAQ,QAAQ,CAAA;AACnC,IAAA,MAAM,IAAA,GAAO,QAAQ,UAAU,CAAA;AAC/B,IAAA,MAAM,KAAA,GAAQ,QAAQ,IAAI,CAAA;AAC1B,IAAA,MAAM,kBAAA,GAAqB,IAAA,CAAK,GAAA,CAAI,UAAA,EAAY,KAAK,CAAA;AAErD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,eAAA,GAAkB,OAAO,IAAI,CAAA;AACvD,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,eAAA,GAAkB,OAAO,IAAI,CAAA;AAC5D,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,gBAAA,GAAmB,OAAO,IAAI,CAAA;AAK7D,IAAA,MAAM,cAAc,IAAA,CAAK,KAAA,CAAM,mBAAA,EAAoB,GAAI,OAAO,IAAI,CAAA;AAClE,IAAA,MAAM,mBAAA,GAAsB,IAAA,CAAK,KAAA,CAAM,SAAA,GAAY,OAAO,IAAI,CAAA;AAC9D,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,KAAA,CAAM,eAAA,GAAkB,OAAO,IAAI,CAAA;AAO/D,IAAA,MAAM,iBAAiB,OAAA,CAAQ,MAAA;AAC/B,IAAA,MAAM,gBAAgB,OAAA,CAAQ,MAAA;AAC9B,IAAA,MAAM,eAAA,GAAkB,OAAO,UAAA,CAC5B,GAAA,CAAI,CAAC,SAAA,KAAc,CAAA,EAAG,UAAU,MAAM,CAAA,CAAA,EAAI,KAAK,KAAA,CAAM,SAAA,CAAU,QAAQ,IAAA,GAAO,IAAI,CAAC,CAAA,EAAA,CAAI,CAAA,CACvF,KAAK,IAAI,CAAA;AACZ,IAAA,MAAM,iBAAA,GAAoB,OAAO,QAAA,CAC9B,GAAA,CAAI,CAAC,KAAA,KAAU,CAAA,EAAG,MAAM,MAAM,CAAA,CAAA,EAAI,KAAK,KAAA,CAAM,KAAA,CAAM,QAAQ,IAAA,GAAO,IAAI,CAAC,CAAA,EAAA,CAAI,CAAA,CAC3E,KAAK,IAAI,CAAA;AAeZ,IAAA,MAAM,cAAA,GAAiB,QAAQ,MAAA,KAAW,wBAAA;AAC1C,IAAA,MAAM,UAAU,QAAA,KAAa,IAAA;AAC7B,IAAA,MAAM,eAAA,2BAAyC,IAAA,KAC7C,gBAAA,IAAoB,kBAAkB,YAAA,CAAa,IAAI,IAAI,CAAA,CAAA,EADrC,iBAAA,CAAA;AAExB,IAAA,MAAM,YAAA,2BAAsC,IAAA,KAC1C,mBAAA;AAAA,MACE,gBAAgB,IAAI,CAAA;AAAA,MACpB,eAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA,gBAAA;AAAA,MACA,eAAA;AAAA,MACA;AAAA,KACF,EAVmB,cAAA,CAAA;AAYrB,IAAA,MAAM,YAAA,GAAe,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,KAAA,CAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,gBAAgB,CAAC,CAAC,CAAA,GAAI,CAAA;AACnG,IAAA,MAAM,UAAA,GAAa,OAAA,GAAU,YAAA,CAAa,YAAY,CAAA,GAAI,CAAA;AAC1D,IAAA,MAAM,SAAA,GAAY,OAAA,GAAU,YAAA,CAAa,UAAU,CAAA,GAAI,CAAA;AACvD,IAAA,MAAM,gBAAA,GAAmB,UAAU,IAAA,CAAK,GAAA,CAAI,YAAY,YAAA,CAAa,SAAS,CAAC,CAAA,GAAI,CAAA;AACnF,IAAA,MAAM,IAAA,GAAO,UAAU,WAAA,GAAc,OAAA;AACrC,IAAA,MAAM,gBAAA,GAAmB,UAAU,gBAAA,GAAmB,kBAAA;AACtD,IAAA,MAAM,cAAc,gBAAA,KAAqB,CAAA;AAQzC,IAAA,MAAMI,KAAAA,GAAO,mBAAA;AAEb,IAAA,MAAM,SAAA,GAAYA,QAAO,yCAAA,GAA4C,gCAAA;AACrE,IAAA,MAAM,OAAA,GAAUA,QAAO,CAAA,2DAAA,CAAA,GAAgE,CAAA,MAAA,CAAA;AAMvF,IAAA,MAAM,YAAA,GAAeA,QACjB,CAAA,mGAAA,CAAA,GACA,EAAA;AAEJ,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,MAAA,GACE,CAAA,gCAAA,EAAmC,SAAS,CAAA,QAAA,EAAW,IAAI,CAAA,cAAA,CAAA,IAC1D,iBACG,CAAA,EAAG,OAAO,CAAA,6BAAA,CAAA,GACV,CAAA,EAAG,OAAO,CAAA,gEAAA,CAAA,CAAA;AAAA,IAClB,WAAW,cAAA,EAAgB;AACzB,MAAA,MAAA,GACE,eACA,CAAA,oNAAA,EAAuN,IAAI,CAAA,eAAA,EAAkB,WAAA,CAAY,gBAAgB,CAAC,CAAA,eAAA,CAAA;AAAA,IAC9Q,CAAA,MAAO;AACL,MAAA,MAAA,GACE,eACA,CAAA,iCAAA,EAAoC,IAAI,CAAA,yBAAA,EAA4B,WAAA,CAAY,gBAAgB,CAAC,CAAA,4DAAA,CAAA;AAAA,IACrG;AAMA,IAAA,MAAM,cAAc,EAAC;AAErB,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,WAAA,CAAY,KAAK,EAAC,MAAA,EAAQ,IAAA,EAAM,KAAA,EAAO,kBAAiB,CAAA;AAAA,IAC1D;AAIA,IAAA,IAAI,CAAC,cAAA,EAAgB;AASnB,MAAA,IAAI,SAAS,IAAA,CAAK,IAAA,CAAK,eAAA,GAAkB,YAAA,IAAgB,OAAO,IAAA,CAAK,CAAA;AAErE,MAAA,OAAO,IAAA,CAAK,IAAI,MAAA,GAAS,IAAA,GAAO,MAAM,oBAAoB,CAAA,GAAI,eAAe,eAAA,EAAiB;AAC5F,QAAA,MAAA,IAAU,CAAA;AAAA,MACZ;AAEA,MAAA,WAAA,CAAY,KAAK,EAAC,UAAA,EAAY,sBAAA,EAAwB,KAAA,EAAO,QAAO,CAAA;AAAA,IACtE;AAEA,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,KAAA;AAAA,MACN,MAAA,EAAQ,QAAA;AAAA,MACR,UAAU,EAAC,SAAA,EAAW,UAAA,EAAY,aAAA,EAAe,gBAAgB,SAAA,EAAS;AAAA,MAC1E,MAAA,EAAQ,QAAA,CAAS,MAAA,EAAQ,QAAA,EAAU,YAAY,CAAA;AAAA;AAAA;AAAA;AAAA,MAI/C,OAAO,eAAA,KAAoB,CAAA;AAAA,MAC3B,WAAA;AAAA,MACA,OAAA,EAAS;AAAA,QACP,SACE,CAAA,yCAAA,EACG,mBAAA,GAAsB,iBAAiB,cAAc,CAAA,EAAA,EAAK,MAAM,CAAA,6BAAA,EAAgC,WAAW,kBAAkB,WAAW,CAAA,eAAA,EAAkB,cAAc,CAAA,eAAA,EAAkB,aAAa,iBAAiB,eAAe,CAAA,yBAAA,EAA4B,iBAAiB,CAAA,GAAA,CAAA,GACvR,MAAA;AAAA,QACF,OAAA,EAAS;AAAA,UACP,eAAA;AAAA,UACA,iBAAA,EAAmB,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAKnB,mBAAA,EAAqB,mBAAA;AAAA,UACrB,mBAAA,EAAqB,aAAA;AAAA,UACrB,iBAAA,EAAmB,WAAA;AAAA,UACnB,iBAAA,EAAmB,WAAA;AAAA,UACnB,WAAA;AAAA,UACA,mBAAA;AAAA,UACA,cAAA;AAAA,UACA,cAAA;AAAA,UACA,aAAA;AAAA,UACA,cAAc,MAAA,CAAO,UAAA;AAAA,UACrB,gBAAgB,MAAA,CAAO,QAAA;AAAA,UACvB,WAAA;AAAA,UACA,SAAA;AAAA,UACA,OAAA;AAAA,UACA,kBAAA;AAAA;AAAA;AAAA,UAGA,GAAI,OAAA,GAAU,EAAC,UAAU,oBAAA,EAAsB,gBAAA,KAAoB;AAAC;AACtE;AACF,KACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,IAAA;AAAA,IACN,UAAU,EAAC,SAAA,EAAW,UAAA,EAAY,aAAA,EAAe,gBAAgB,SAAA,EAAS;AAAA,IAC1E,MAAA,EAAQ,QAAA,CAAS,MAAA,EAAQ,QAAA,EAAU,YAAY,CAAA;AAAA,IAC/C,OAAO,eAAA,KAAoB,CAAA;AAAA,IAC3B,aAAa;AAAC,GAChB;AACF;AAQA,SAAS,SAAS,MAAA,EAAQ;AAExB,EAAA,MAAM,EAAC,OAAA,EAAS,GAAG,IAAA,EAAI,GAAI,MAAA;AAE3B,EAAA,OAAO,IAAA;AACT;AAiBA,SAAS,QAAA,CAAS,MAAA,EAAQ,QAAA,EAAU,YAAA,EAAc;AAGhD,EAAA,MAAM,YAAA,GAAe,OAAO,UAAA,CAAW,IAAA,CAAK,CAAC,SAAA,KAAc,SAAA,CAAU,WAAW,eAAe,CAAA;AAE/F,EAAA,OAAO;AAAA,IACL,WAAW,mBAAA,EAAoB;AAAA,IAC/B,YAAA,EAAc,YAAA,GAAe,YAAA,CAAa,KAAA,GAAQ,IAAA;AAAA,IAClD,KAAA,EAAO,QAAA,CAAS,QAAA,GAAW,MAAA,GAAS,SAAA;AAAA,IACpC,YAAA;AAAA,IACA,YAAA,EAAc,QAAA,CAAS,OAAA,IAAW,QAAA,CAAS,KAAA,GAAQ,YAAA;AAAA,IACnD,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,UAAU,MAAA,CAAO;AAAA,GACnB;AACF;AAmBA,SAAS,YAAY,KAAA,EAAO;AAC1B,EAAA,OAAO,KAAA,CAAM,eAAe,OAAO,CAAA;AACrC;AAWO,SAAS,oBAAA,CACd,iBACA,OAAA,EACA,SAAA,EACA,cAAc,CAAA,EACd,gBAAA,GAAmB,IAAA,EACnB,YAAA,GAAe,KAAA,EACf;AAMA,EAAA,MAAM,0BAAA,GAA6B,qBAAoB,GAAI,KAAA;AAE3D,EAAA,IAAI,mBAAmB,0BAAA,EAA4B;AACjD,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,UAAA,GAAa,OAAA,KAAY,IAAA,IAAQ,OAAA,IAAW,YAAY,SAAA,GAAY,OAAA;AAI1E,EAAA,MAAM,eAAA,GAAkB,mBAAA;AAAA,IACtB,eAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,gBAAA;AAAA,IACA,IAAA;AAAA,IACA;AAAA,GACF;AAWA,EAAA,IAAI,mBAAmB,0BAAA,EAA4B;AACjD,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,eAAA,GAAkB,OAAO,IAAI,CAAA;AACvD,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,eAAA,GAAkB,OAAO,IAAI,CAAA;AAC5D,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,0BAAA,GAA6B,OAAO,IAAI,CAAA;AAElE,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,CAAA,2CAAA,EAAoC,MAAM,CAAA,KAAA,EAAQ,MAAM,CAAA,sCAAA,EAC5B,WAAA,CAAY,UAAU,CAAC,CAAA,IAAA,EAAO,WAAA,CAAY,SAAS,CAAC,uBAC7D,WAAW,CAAA,wJAAA;AAAA,GAGhC;AACF;AA3mCA,IA8GM,8BAAA,EAkBA,oBAAA,EAgFA,UAAA,EACA,cAAA,EACA,cAAA,EA2QA,WAAA;AA7dN,IAAA,gBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,yBAAA,GAAA;AAIA,IAAA,cAAA,EAAA;AAQgB,IAAA,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AAcP,IAAA,MAAA,CAAA,qBAAA,EAAA,uBAAA,CAAA;AA+BO,IAAA,MAAA,CAAA,eAAA,EAAA,iBAAA,CAAA;AAqDhB,IAAM,8BAAA,GAAiC,MAAM,IAAA,GAAO,IAAA;AAkBpD,IAAM,oBAAA,GAAuB,KAAK,IAAA,GAAO,IAAA;AAgBhC,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AAgET,IAAM,UAAA,GAAa,KAAK,IAAA,GAAO,IAAA;AAC/B,IAAM,cAAA,GAAiB,EAAA;AACvB,IAAM,cAAA,GAAiB,CAAA;AAuBP,IAAA,MAAA,CAAA,sBAAA,EAAA,wBAAA,CAAA;AAgBP,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAOO,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AA6FA,IAAA,MAAA,CAAA,kBAAA,EAAA,oBAAA,CAAA;AAoEA,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AA4DhB,IAAM,WAAA,GAAc,MAAA,CAAO,MAAA,CAAO,EAAC,MAAM,CAAA,EAAG,OAAA,kBAAS,MAAA,CAAA,MAAM,CAAA,EAAN,SAAA,CAAA,EAAS,QAAA,kBAAU,MAAA,CAAA,MAAM,CAAA,EAAN,aAAQ,CAAA;AAoChE,IAAA,MAAA,CAAA,0BAAA,EAAA,4BAAA,CAAA;AA0FA,IAAA,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAmZP,IAAA,MAAA,CAAA,QAAA,EAAA,UAAA,CAAA;AAsBA,IAAA,MAAA,CAAA,QAAA,EAAA,UAAA,CAAA;AAiCA,IAAA,MAAA,CAAA,WAAA,EAAA,aAAA,CAAA;AAaO,IAAA,MAAA,CAAA,oBAAA,EAAA,sBAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACvhCT,SAAS,cAAc,KAAA,EAAO;AACnC,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,eAAA,CAAgB,IAAA,CAAK,KAAK,CAAA,EAAG;AAC7D,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,GAAS,OAAO,KAAK,CAAA;AAG3B,EAAA,OAAO,MAAA,KAAW,IAAI,CAAA,GAAI,MAAA;AAC5B;AA8BO,SAAS,uBAAA,CAAwB,SAAA,EAAW,QAAA,EAAU,KAAA,EAAO;AAClE,EAAA,MAAM,WAAA,GAAc,YAAY,gBAAgB,CAAA;AAIhD,EAAA,IAAI,WAAA,KAAgB,QAAQ,OAAO,WAAA,KAAgB,YAAY,KAAA,CAAM,OAAA,CAAQ,WAAW,CAAA,EAAG;AACzF,IAAA,MAAM,IAAI,kBAAkB,0DAAA,EAA4D;AAAA,MACtF,YAAA,EAAc,aAAa,OAAO,SAAA,KAAc,WAAW,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,GAAI,EAAC;AAAA,MACrF,IAAA,EAAM,QAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,iBAAA,GAAoB,aAAA,CAAc,WAAA,CAAY,QAAQ,CAAC,CAAA;AAE7D,EAAA,IAAI,KAAA,CAAM,iBAAiB,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,iBAAiB,CAAA,IAAK,iBAAA,GAAoB,CAAA,EAAG;AACjG,IAAA,MAAM,IAAI,kBAAkB,6BAAA,EAA+B;AAAA,MACzD,MAAA,EAAQ,YAAY,QAAQ,CAAA;AAAA,MAC5B,IAAA,EAAM,QAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AASA,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,QAAQ,CAAA,GAAI,gBAAgB,CAAA;AACvD,EAAA,MAAM,SAAA,GAAY,MAAA,KAAW,MAAA,IAAa,MAAA,KAAW,IAAA,GAAO,EAAC,GAAI,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,GAAI,MAAA,GAAS,CAAC,MAAM,CAAA;AAEzG,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,IAAA,MAAM,IAAI,kBAAkB,wCAAA,EAA0C;AAAA,MACpE,IAAA,EAAM,QAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AASA,EAAA,MAAM,iBAAiB,SAAA,CAAU,SAAA;AAAA,IAC/B,CAAC,UAAU,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,KAAK;AAAA,GAC/E;AAEA,EAAA,IAAI,mBAAmB,EAAA,EAAI;AACzB,IAAA,MAAM,IAAI,kBAAkB,yDAAA,EAA2D;AAAA,MACrF,UAAA,EAAY,cAAA;AAAA,MACZ,YAAY,SAAA,CAAU,MAAA;AAAA,MACtB,IAAA,EAAM,QAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AAWA,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAI;AAErB,EAAA,SAAA,CAAU,OAAA,CAAQ,CAAC,KAAA,EAAO,UAAA,KAAe;AACvC,IAAA,MAAM,IAAA,GAAO,MAAM,WAAW,CAAA;AAE9B,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,EAAA,EAAI;AAC3C,MAAA,MAAM,IAAI,kBAAkB,0DAAA,EAA4D;AAAA,QACtF,UAAA;AAAA,QACA,SAAA,EAAW,IAAA;AAAA,QACX,IAAA,EAAM,QAAA;AAAA,QACN;AAAA,OACD,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,EAAG;AAClB,MAAA,MAAM,IAAI,kBAAkB,4DAAA,EAA8D;AAAA,QACxF,KAAA,EAAO,IAAA;AAAA,QACP,cAAc,CAAC,IAAA,CAAK,GAAA,CAAI,IAAI,GAAG,UAAU,CAAA;AAAA,QACzC,IAAA,EAAM,QAAA;AAAA,QACN;AAAA,OACD,CAAA;AAAA,IACH;AAEA,IAAA,IAAA,CAAK,GAAA,CAAI,MAAM,UAAU,CAAA;AAAA,EAC3B,CAAC,CAAA;AAED,EAAA,OAAO,SAAA;AACT;AAeO,SAAS,4BAAA,CAA6B,iBAAA,EAAmB,QAAA,EAAU,aAAA,GAAgB,CAAA,EAAG;AAG3F,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,wBAAwB,SAAA,GAAY,KAAA;AAE1C,EAAA,IAAI,oBAAoB,qBAAA,EAAuB;AAC7C,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,iBAAA,GAAoB,OAAO,IAAI,CAAA;AACzD,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,qBAAA,GAAwB,OAAO,IAAI,CAAA;AAC5D,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,SAAA,GAAY,OAAO,IAAI,CAAA;AASjD,IAAA,IAAI,aAAA,GAAgB,CAAA,IAAK,iBAAA,GAAoB,aAAA,IAAiB,qBAAA,EAAuB;AACnF,MAAA,MAAM,IAAI,kBAAA;AAAA,QACR,2BAA2B,MAAM,CAAA,WAAA,EAAc,KAAK,CAAA,yMAAA,EAGT,MAAM,sBAAsB,KAAK,CAAA,kMAAA,CAAA;AAAA,QAG5E;AAAA,UACE,IAAA,EAAM,QAAA;AAAA,UACN,eAAA,EAAiB,iBAAA;AAAA,UACjB,iBAAA,EAAmB,MAAA;AAAA,UACnB,mBAAA,EAAqB,IAAA;AAAA,UACrB,mBAAA,EAAqB,aAAA;AAAA,UACrB,UAAA,EAAY,qBAAA;AAAA,UACZ,YAAA,EAAc,KAAA;AAAA,UACd,WAAA,EAAa,MAAA;AAAA,UACb,MAAA,EAAQ;AAAA;AACV,OACF;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,kBAAA;AAAA,MACR,2BAA2B,MAAM,CAAA,WAAA,EAAc,KAAK,CAAA,4HAAA,EAET,MAAM,sBAAsB,KAAK,CAAA,6OAAA,CAAA;AAAA,MAM5E;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,eAAA,EAAiB,iBAAA;AAAA,QACjB,iBAAA,EAAmB,MAAA;AAAA;AAAA;AAAA,QAGnB,mBAAA,EAAqB,KAAA;AAAA,QACrB,mBAAA,EAAqB,aAAA;AAAA,QACrB,UAAA,EAAY,qBAAA;AAAA,QACZ,YAAA,EAAc,KAAA;AAAA,QACd,WAAA,EAAa,MAAA;AAAA,QACb,eAAA,EAAiB;AAAA;AACnB,KACF;AAAA,EACF;AACF;AAYO,SAAS,uBAAA,CAAwB,iBAAA,EAAmB,QAAA,EAAU,SAAA,EAAW;AAG9E,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,4BAA4B,SAAA,GAAY,GAAA;AAE9C,EAAA,IAAI,oBAAoB,yBAAA,EAA2B;AACjD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,iBAAA,GAAoB,OAAO,IAAI,CAAA;AACzD,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,yBAAA,GAA4B,OAAO,IAAI,CAAA;AAChE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,SAAA,GAAY,OAAO,IAAI,CAAA;AAEjD,IAAA,MAAM,IAAI,kBAAA;AAAA,MACR,+CAA+C,MAAM,CAAA,KAAA,EAAQ,KAAK,CAAA,sHAAA,EAEvB,MAAM,oBAAoB,KAAK,CAAA,oKAAA,CAAA;AAAA,MAE1E;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,eAAA,EAAiB,iBAAA;AAAA,QACjB,iBAAA,EAAmB,MAAA;AAAA,QACnB,UAAA,EAAY,yBAAA;AAAA,QACZ,YAAA,EAAc,KAAA;AAAA,QACd,WAAA,EAAa,MAAA;AAAA,QACb,eAAA,EAAiB,EAAA;AAAA,QACjB;AAAA;AACF,KACF;AAAA,EACF;AACF;AAeO,SAAS,qBAAA,CAAsB,KAAA,EAAO,kBAAA,EAAoB,QAAA,EAAU;AACzE,EAAA,MAAM,aAAA,GAAgB,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAC,CAAA;AACnD,EAAA,MAAM,aAAA,GAAgB,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAC,CAAA;AACnD,EAAA,MAAM,WAAA,GAAc,aAAA,CAAc,KAAA,CAAM,aAAa,CAAC,CAAA;AAGtD,EAAA,IAAI,KAAA,CAAM,aAAa,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,aAAa,CAAA,IAAK,aAAA,GAAgB,CAAA,EAAG;AACrF,IAAA,MAAM,IAAI,kBAAkB,uBAAA,EAAyB;AAAA,MACnD,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,MAAA,EAAQ,aAAA;AAAA,MACR,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,KAAA,CAAM,aAAa,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,aAAa,CAAA,IAAK,aAAA,GAAgB,CAAA,EAAG;AACrF,IAAA,MAAM,IAAI,kBAAkB,uBAAA,EAAyB;AAAA,MACnD,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,MAAA,EAAQ,aAAA;AAAA,MACR,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,WAAW,CAAA,IAAK,WAAA,GAAc,CAAA,EAAG;AAC/E,IAAA,MAAM,IAAI,kBAAkB,sBAAA,EAAwB;AAAA,MAClD,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,WAAA,EAAa,WAAA;AAAA,MACb,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,aAAA,GAAgB,gBAAgB,kBAAA,EAAoB;AACtD,IAAA,MAAM,IAAI,kBAAkB,mCAAA,EAAqC;AAAA,MAC/D,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,MAAA,EAAQ,aAAA;AAAA,MACR,MAAA,EAAQ,aAAA;AAAA,MACR,UAAA,EAAY,kBAAA;AAAA,MACZ,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF;AAqBA,SAAS,aAAa,MAAA,EAAQ;AAC5B,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,CAAO,CAAC,KAAA,KAAU,MAAM,MAAA,GAAS,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AAE3F,EAAA,IAAI,QAAA,GAAW,IAAA;AAEf,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,IAAI,aAAa,IAAA,IAAQ,KAAA,CAAM,QAAQ,QAAA,CAAS,KAAA,GAAQ,SAAS,MAAA,EAAQ;AACvE,MAAA,OAAO,CAAC,UAAU,KAAK,CAAA;AAAA,IACzB;AAEA,IAAA,IAAI,QAAA,KAAa,QAAQ,KAAA,CAAM,KAAA,GAAQ,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,GAAQ,QAAA,CAAS,MAAA,EAAQ;AACtF,MAAA,QAAA,GAAW,KAAA;AAAA,IACb;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAoBO,SAAS,mBAAA,CAAoB,QAAQ,QAAA,EAAU;AACpD,EAAA,MAAM,OAAA,GAAU,YAAA;AAAA,IACd,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,MACrB,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,KAAA,EAAO,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAC,CAAA;AAAA,MACpC,MAAA,EAAQ,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAC;AAAA,KACvC,CAAE;AAAA,GACJ;AAEA,EAAA,IAAI,YAAY,IAAA,EAAM;AACpB,IAAA,MAAM,CAAC,KAAA,EAAO,MAAM,CAAA,GAAI,OAAA;AAExB,IAAA,MAAM,IAAI,kBAAkB,sBAAA,EAAwB;AAAA,MAClD,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,QAAQ,MAAA,CAAO,KAAA;AAAA,MACf,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,UAAU,KAAA,CAAM,KAAA;AAAA,MAChB,gBAAgB,KAAA,CAAM,KAAA;AAAA,MACtB,gBAAgB,KAAA,CAAM,MAAA;AAAA,MACtB,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF;AAkBO,SAAS,iBAAA,CAAkB,QAAQ,QAAA,EAAU;AAClD,EAAA,MAAM,OAAA,GAAU,YAAA;AAAA,IACd,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,MACrB,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,KAAA,EAAO,aAAA,CAAc,KAAA,CAAM,WAAW,CAAC,CAAA;AAAA,MACvC,MAAA,EAAQ,aAAA,CAAc,KAAA,CAAM,UAAU,CAAC;AAAA,KACzC,CAAE;AAAA,GACJ;AAEA,EAAA,IAAI,YAAY,IAAA,EAAM;AACpB,IAAA,MAAM,CAAC,KAAA,EAAO,MAAM,CAAA,GAAI,OAAA;AAExB,IAAA,MAAM,IAAI,kBAAkB,oBAAA,EAAsB;AAAA,MAChD,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,WAAW,MAAA,CAAO,KAAA;AAAA,MAClB,UAAU,MAAA,CAAO,MAAA;AAAA,MACjB,UAAU,KAAA,CAAM,KAAA;AAAA,MAChB,mBAAmB,KAAA,CAAM,KAAA;AAAA,MACzB,kBAAkB,KAAA,CAAM,MAAA;AAAA,MACxB,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF;AAeO,SAAS,mBAAA,CAAoB,SAAA,EAAW,QAAA,EAAU,KAAA,GAAQ,iBAAA,EAAmB;AAClF,EAAA,IAAI,KAAA,CAAM,SAAS,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,SAAS,CAAA,IAAK,SAAA,GAAY,CAAA,EAAG;AACzE,IAAA,MAAM,IAAI,kBAAkB,2BAAA,EAA6B;AAAA,MACvD,SAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AACF;AAeO,SAAS,kBAAA,CAAmB,UAAA,EAAY,QAAA,EAAU,KAAA,GAAQ,iBAAA,EAAmB;AAClF,EAAA,IAAI,KAAA,CAAM,UAAU,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,UAAU,CAAA,IAAK,UAAA,GAAa,CAAA,EAAG;AAC5E,IAAA,MAAM,IAAI,kBAAkB,0BAAA,EAA4B;AAAA,MACtD,UAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,EACH;AACF;AAqBO,SAAS,0BAAA,CACd,UAAA,EACA,SAAA,EACA,gBAAA,EACA,gBAAA,EACA,YAAA,EACA,UAAA,EACA,QAAA,EACA,QAAA,GAAW,IAAA,EACX,cAAA,GAAiB,CAAA,EACjB,iBAAiB,CAAA,EACjB;AACA,EAAA,kBAAA,CAAmB,YAAY,QAAQ,CAAA;AACvC,EAAA,mBAAA,CAAoB,WAAW,QAAQ,CAAA;AAIvC,EAAA,IAAI,UAAA,KAAe,CAAA,IAAK,SAAA,GAAY,CAAA,EAAG;AACrC,IAAA,MAAM,IAAI,kBAAkB,oDAAA,EAAsD;AAAA,MAChF,UAAA;AAAA,MACA,SAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,aAAa,OAAA,EAAS;AACxB,IAAA,MAAM,IAAI,kBAAkB,kCAAA,EAAoC;AAAA,MAC9D,UAAA;AAAA,MACA,OAAA,EAAS,OAAA;AAAA,MACT,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,KAAA,CAAM,gBAAgB,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,gBAAgB,CAAA,IAAK,gBAAA,GAAmB,CAAA,EAAG;AAC9F,IAAA,MAAM,IAAI,kBAAkB,4BAAA,EAA8B;AAAA,MACxD,MAAA,EAAQ,gBAAA;AAAA,MACR,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,mBAAmB,YAAA,EAAc;AACnC,IAAA,MAAM,IAAI,kBAAkB,kCAAA,EAAoC;AAAA,MAC9D,gBAAA;AAAA,MACA,UAAA,EAAY,YAAA;AAAA,MACZ,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAKA,EAAA,IAAI,gBAAA,KAAqB,YAAY,UAAA,EAAY;AAC/C,IAAA,MAAM,IAAI,kBAAkB,mDAAA,EAAqD;AAAA,MAC/E,gBAAA;AAAA,MACA,gBAAgB,SAAA,GAAY,UAAA;AAAA,MAC5B,SAAA;AAAA,MACA,UAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAQA,EAAA,IAAI,aAAa,IAAA,EAAM;AACrB,IAAA,IAAI,gBAAA,GAAmB,mBAAmB,QAAA,EAAU;AAClD,MAAA,MAAM,IAAI,kBAAkB,gDAAA,EAAkD;AAAA,QAC5E,gBAAA;AAAA,QACA,gBAAA;AAAA,QACA,QAAA;AAAA,QACA,IAAA,EAAM,QAAA;AAAA,QACN,KAAA,EAAO;AAAA,OACR,CAAA;AAAA,IACH;AAAA,EACF;AAMA,EAAA,MAAM,qBAAqB,UAAA,GAAa,UAAA;AACxC,EAAA,MAAM,iBAAA,GAAA,CAAqB,iBAAiB,cAAA,IAAkB,UAAA;AAC9D,EAAA,IAAI,gBAAA,GAAmB,iBAAA,GAAoB,kBAAA,GAAqB,YAAA,EAAc;AAC5E,IAAA,MAAM,IAAI,kBAAkB,uBAAA,EAAyB;AAAA,MACnD,gBAAA;AAAA,MACA,aAAA,EAAe,kBAAA;AAAA,MACf,gBAAgB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,YAAA,GAAe,mBAAmB,iBAAiB,CAAA;AAAA,MAC/E,UAAA;AAAA,MACA,cAAA;AAAA,MACA,cAAA;AAAA,MACA,UAAA;AAAA,MACA,UAAA,EAAY,YAAA;AAAA,MACZ,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAOA,EAAA,MAAM,kBAAA,GAAA,CAAsB,iBAAiB,UAAA,IAAc,UAAA;AAC3D,EAAA,IAAI,mBAAmB,kBAAA,EAAoB;AACzC,IAAA,MAAM,IAAI,kBAAkB,0CAAA,EAA4C;AAAA,MACtE,gBAAA;AAAA,MACA,aAAA,EAAe,kBAAA;AAAA,MACf,UAAA;AAAA,MACA,cAAA;AAAA,MACA,UAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF;AAUO,SAAS,wBAAA,CAAyB,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU;AACpE,EAAA,MAAM,SAAA,GAAY,aAAA,CAAc,KAAA,CAAM,WAAW,CAAC,CAAA;AAClD,EAAA,MAAM,QAAA,GAAW,aAAA,CAAc,KAAA,CAAM,UAAU,CAAC,CAAA;AAGhD,EAAA,IAAI,KAAA,CAAM,SAAS,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,SAAS,CAAA,IAAK,SAAA,GAAY,CAAA,EAAG;AACzE,IAAA,MAAM,IAAI,kBAAkB,oBAAA,EAAsB;AAAA,MAChD,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,SAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,KAAA,CAAM,QAAQ,CAAA,IAAK,CAAC,OAAO,aAAA,CAAc,QAAQ,CAAA,IAAK,QAAA,GAAW,CAAA,EAAG;AACtE,IAAA,MAAM,IAAI,kBAAkB,mBAAA,EAAqB;AAAA,MAC/C,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,QAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AASA,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,KAAA,CAAM,MAAM,CAAC,CAAA;AAExC,EAAA,IAAI,MAAM,IAAI,CAAA,IAAK,CAAC,MAAA,CAAO,aAAA,CAAc,IAAI,CAAA,EAAG;AAC9C,IAAA,MAAM,IAAI,kBAAkB,cAAA,EAAgB;AAAA,MAC1C,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,IAAA,EAAM,MAAM,MAAM,CAAA;AAAA,MAClB,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AASA,EAAA,IAAI,WAAW,aAAA,EAAe;AAC5B,IAAA,MAAM,IAAI,kBAAkB,2BAAA,EAA6B;AAAA,MACvD,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,QAAA;AAAA,MACA,WAAA,EAAa,aAAA;AAAA,MACb,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAWA,EAAA,IAAI,IAAA,GAAO,WAAO,IAAO,IAAA,GAAO,KAAK,QAAA,GAAW,CAAA,GAAI,CAAA,IAAK,EAAA,GAAK,CAAA,EAAG;AAC/D,IAAA,MAAM,IAAI,kBAAkB,mBAAA,EAAqB;AAAA,MAC/C,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,IAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAYA,EAAA,IAAI,IAAA,KAAS,CAAA,IAAK,IAAA,KAAS,EAAA,EAAI;AAC7B,IAAA,MAAM,IAAI,kBAAkB,0BAAA,EAA4B;AAAA,MACtD,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,IAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,mBAAmB,UAAA,GAAa,CAAA;AACtC,EAAA,IAAI,SAAA,GAAY,WAAW,gBAAA,EAAkB;AAC3C,IAAA,MAAM,IAAI,kBAAkB,sCAAA,EAAwC;AAAA,MAClE,KAAA,EAAO,MAAM,WAAW,CAAA;AAAA,MACxB,SAAA;AAAA,MACA,QAAA;AAAA,MACA,gBAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AACF;AAtwBA,IAAA,oBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,6BAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AACA,IAAA,aAAA,EAAA;AAuBgB,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAuCA,IAAA,MAAA,CAAA,uBAAA,EAAA,yBAAA,CAAA;AA+GA,IAAA,MAAA,CAAA,4BAAA,EAAA,8BAAA,CAAA;AA4EA,IAAA,MAAA,CAAA,uBAAA,EAAA,yBAAA,CAAA;AA2CA,IAAA,MAAA,CAAA,qBAAA,EAAA,uBAAA,CAAA;AAmEP,IAAA,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AAoCO,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AAyCA,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAsCA,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AAuBA,IAAA,MAAA,CAAA,kBAAA,EAAA,oBAAA,CAAA;AA6BA,IAAA,MAAA,CAAA,0BAAA,EAAA,4BAAA,CAAA;AAuIA,IAAA,MAAA,CAAA,wBAAA,EAAA,0BAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;AC9lBhB,SAAS,SAAA,CAAU,IAAA,EAAM,EAAC,KAAA,EAAO,aAAW,EAAG;AAC7C,EAAAJ,OAAAA,CAAO,KAAA,GAAQ,WAAA,GAAc,cAAA,EAAgB,kEAAkE,CAAA;AAE/G,EAAA,IAAI,IAAA,CAAK,UAAU,KAAA,EAAO;AACxB,IAAA,OAAO,CAAC,IAAA,KAAS,IAAA,CAAK,OAAA,CAAQ,GAAG,IAAI,CAAA;AAAA,EACvC;AAEA,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,CAAA,EAAG,KAAK,CAAA;AAEjC,EAAA,OAAO,CAAC,IAAA,KAAS;AACf,IAAA,IAAI,IAAA,GAAO,OAAO,WAAA,EAAa;AAC7B,MAAA,IAAA,GAAO,IAAA;AACP,MAAA,IAAA,GAAO,IAAA,CAAK,SAAS,IAAA,EAAM,IAAA,CAAK,IAAI,IAAA,CAAK,MAAA,EAAQ,IAAA,GAAO,KAAK,CAAC,CAAA;AAAA,IAChE;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,CAAA,EAAG,OAAO,IAAI,CAAA;AAEzC,IAAA,OAAO,KAAA,KAAU,EAAA,GAAK,EAAA,GAAK,IAAA,GAAO,KAAA;AAAA,EACpC,CAAA;AACF;AAgBA,SAAS,QAAQ,OAAA,EAAS,OAAA,EAAS,MAAM,IAAA,EAAM,SAAA,EAAW,UAAU,IAAA,EAAM;AACxE,EAAA,MAAM,KAAA,GAAQ,QAAQ,IAAI,CAAA;AAE1B,EAAA,IAAA,CAAK,KAAA,KAAU,EAAA,GAAK,OAAA,GAAU,KAAA,IAAS,OAAO,cAAA,EAAgB;AAC5D,IAAA,MAAM,IAAI,iBAAA,CAAkB,CAAA,EAAG,IAAI,CAAA,uBAAA,CAAA,EAA2B;AAAA,MAC5D,KAAA,EAAO,SAAA;AAAA,MACP,SAAA,EAAW,cAAA;AAAA,MACX,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,UAAU,EAAA,EAAI;AAChB,IAAA,MAAM,IAAI,iBAAA,CAAkB,CAAA,EAAG,IAAI,CAAA,oBAAA,CAAA,EAAwB;AAAA,MACzD,KAAA,EAAO,SAAA;AAAA,MACP,SAAS,IAAA,GAAO,IAAA;AAAA,MAChB,SAAS,IAAA,GAAO,OAAA;AAAA,MAChB,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,KAAA;AACT;AAcA,SAAS,SAAS,OAAA,EAAS,OAAA,EAAS,OAAA,EAAS,SAAA,EAAW,UAAU,IAAA,EAAM;AACtE,EAAA,MAAM,IAAI,kBAAkB,OAAA,EAAS;AAAA,IACnC,KAAA,EAAO,SAAA;AAAA,IACP,SAAS,IAAA,GAAO,OAAA;AAAA,IAChB,SAAS,IAAA,GAAO,OAAA;AAAA,IAChB,IAAA,EAAM,QAAA;AAAA,IACN,KAAA,EAAO;AAAA,GACR,CAAA;AACH;AAwCO,SAAS,iBAAA,CACd,YAAA,EACA,KAAA,EACA,GAAA,EACA,WAAA,EACA,IAAA,EACA,SAAA,EACA,QAAA,EACA,MAAA,GAAS,WAAA,EACT,IAAA,GAAO,CAAA,EACP;AAOA,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,QAAA,CAAS,CAAA,EAAG,GAAG,CAAA;AACzC,EAAA,MAAM,OAAA,GAAU,SAAA,CAAU,IAAA,EAAM,MAAM,CAAA;AAEtC,EAAA,MAAM,UAAU,EAAC;AAEjB,EAAA,MAAM,QAAQ,EAAC;AACf,EAAA,IAAI,OAAA,GAAU,KAAA;AAEd,EAAA,OAAO,UAAU,GAAA,EAAK;AACpB,IAAA,MAAM,QAAA,GAAW,KAAK,OAAA,EAAS,CAAA;AAC/B,IAAA,MAAM,SAAS,IAAA,KAAS,IAAA,IAAQ,IAAA,CAAK,GAAA,CAAI,QAAQ,MAAM,CAAA;AACvD,IAAA,IAAI,MAAA,GAAS,IAAA;AACb,IAAA,IAAI,IAAA,GAAO,IAAA;AAEX,IAAA,QAAQ,QAAA;AAAU,MAChB,KAAK,CAAA,EAAG;AACN,QAAA,IAAI,OAAA,GAAU,IAAI,GAAA,EAAK;AACrB,UAAA,QAAA,CAAS,wCAAA,EAA0C,OAAA,EAAS,GAAA,EAAK,SAAA,EAAW,UAAU,IAAI,CAAA;AAAA,QAC5F;AACA,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,MAAA,GAAS,IAAA,CAAK,YAAY,OAAO,CAAA;AAAA,QACnC;AACA,QAAA,OAAA,IAAW,CAAA;AACX,QAAA;AAAA,MACF;AAAA,MACA,KAAK,CAAA,EAAG;AACN,QAAA,IAAI,OAAA,GAAU,IAAI,GAAA,EAAK;AACrB,UAAA,QAAA,CAAS,uCAAA,EAAyC,OAAA,EAAS,GAAA,EAAK,SAAA,EAAW,UAAU,IAAI,CAAA;AAAA,QAC3F;AACA,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,MAAA,GAAS,IAAA,CAAK,aAAa,OAAO,CAAA;AAAA,QACpC;AACA,QAAA,OAAA,IAAW,CAAA;AACX,QAAA;AAAA,MACF;AAAA,MACA,KAAK,CAAA,EAAG;AACN,QAAA,MAAM,UAAA,GAAa,QAAQ,OAAA,EAAS,GAAA,EAAK,SAAS,eAAA,EAAiB,SAAA,EAAW,UAAU,IAAI,CAAA;AAC5F,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,OAAA,EAAS,UAAU,CAAA;AAAA,QAClD;AACA,QAAA,OAAA,GAAU,UAAA,GAAa,CAAA;AACvB,QAAA;AAAA,MACF;AAAA,MACA,KAAK,CAAA;AAAA,MACL,KAAK,CAAA,EAAG;AACN,QAAA,MAAM,WAAA,GAAc,QAAA,KAAa,CAAA,GAAI,CAAA,GAAI,CAAA;AACzC,QAAA,IAAI,OAAA,GAAU,cAAc,GAAA,EAAK;AAC/B,UAAA,MAAM,IAAA,GAAO,QAAA,KAAa,CAAA,GAAI,qBAAA,GAAwB,oBAAA;AACtD,UAAA,QAAA,CAAS,2BAA2B,IAAI,CAAA,CAAA,EAAI,SAAS,GAAA,EAAK,SAAA,EAAW,UAAU,IAAI,CAAA;AAAA,QACrF;AAEA,QAAA,MAAM,UAAA,GAAa,OAAA;AAAA,UACjB,OAAA;AAAA,UACA,GAAA;AAAA,UACA,OAAA,GAAU,WAAA;AAAA,UACV,oBAAA;AAAA,UACA,SAAA;AAAA,UACA,QAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,MAAA,GAAS,QAAA,KAAa,IAAI,IAAA,CAAK,WAAA,CAAY,OAAO,CAAA,GAAI,IAAA,CAAK,aAAa,OAAO,CAAA;AAC/E,UAAA,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,MAAA,EAAQ,OAAA,GAAU,aAAa,UAAU,CAAA;AAAA,QAChE;AACA,QAAA,OAAA,GAAU,UAAA,GAAa,CAAA;AACvB,QAAA;AAAA,MACF;AAAA,MACA,SAAS;AACP,QAAA,MAAM,IAAI,cAAc,0BAAA,EAA4B;AAAA,UAClD,QAAA,EAAU,QAAA,CAAS,QAAA,CAAS,EAAE,CAAA;AAAA,UAC9B,MAAA,EAAQ,OAAO,OAAA,GAAU,CAAA;AAAA,UACzB,IAAA,EAAM,QAAA;AAAA,UACN,KAAA,EAAO;AAAA,SACR,CAAA;AAAA,MACH;AAAA;AAGF,IAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AACnB,IAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,EACjB;AAKA,EAAAA,OAAAA,CAAO,YAAY,GAAA,EAAK,CAAA,eAAA,EAAkB,SAAS,CAAA,qBAAA,EAAwB,OAAO,CAAA,sBAAA,EAAyB,GAAG,CAAA,CAAA,CAAG,CAAA;AAEjH,EAAA,IAAI,OAAA,CAAQ,WAAW,WAAA,EAAa;AAClC,IAAA,MAAM,IAAI,kBAAkB,uBAAA,EAAyB;AAAA,MACnD,KAAA,EAAO,SAAA;AAAA,MACP,aAAa,OAAA,CAAQ,MAAA;AAAA,MACrB,WAAA,EAAa,WAAA;AAAA,MACb,IAAA,EAAM,QAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,EAAC,SAAS,KAAA,EAAK;AACxB;AAgCO,SAAS,iBAAA,CAAkB,cAAc,KAAA,EAAO,GAAA,EAAK,aAAa,SAAA,EAAW,QAAA,EAAU,OAAO,CAAA,EAAG;AACtG,EAAA,OAAO,iBAAA,CAAkB,YAAA,EAAc,KAAA,EAAO,GAAA,EAAK,WAAA,EAAa,cAAA,EAAgB,SAAA,EAAW,QAAA,EAAU,MAAA,EAAW,IAAI,CAAA,CACjH,OAAA,CAAQ,MAAA;AACb;AAzUA,IASM,gBAsCO,WAAA,EA0PP,cAAA;AAzSN,IAAA,iBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,0BAAA,GAAA;AAGA,IAAA,cAAA,EAAA;AAMA,IAAM,cAAA,GAAiB,OAAA;AAsChB,IAAM,WAAA,GAAc,MAAA,CAAO,MAAA,CAAO,EAAC,KAAA,EAAO,CAAA,IAAK,EAAA,GAAK,CAAA,EAAG,WAAA,EAAa,CAAA,IAAK,EAAA,EAAG,CAAA;AAY1E,IAAA,MAAA,CAAA,SAAA,EAAA,WAAA,CAAA;AAoCA,IAAA,MAAA,CAAA,OAAA,EAAA,SAAA,CAAA;AAqCA,IAAA,MAAA,CAAA,QAAA,EAAA,UAAA,CAAA;AAgDO,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAqHhB,IAAM,cAAA,uBAAqB,GAAA,EAAI;AA6Bf,IAAA,MAAA,CAAA,iBAAA,EAAA,mBAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACvQT,SAAS,mBAAA,CAAoB,OAAA,EAAS,KAAA,EAAO,IAAA,EAAM,QAAQ,UAAA,EAAY;AAC5E,EAAA,MAAM,MAAA,GAAS,QAAQ,OAAA,CAAQ,MAAA;AAC/B,EAAA,MAAM,MAAA,GAAS,IAAI,KAAA,CAAM,MAAM,CAAA;AAK/B,EAAA,MAAM,cAAc,EAAC;AAErB,EAAA,MAAM,UAAU,EAAC;AAEjB,EAAA,MAAM,QAAQ,EAAC;AACf,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,OAAA,GAAU,KAAA;AAEd,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,EAAQ,KAAA,EAAA,EAAS;AAC3C,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA;AAChC,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA;AAEpC,IAAA,IAAI,SAAS,IAAA,EAAM;AAEjB,MAAA,MAAA,CAAO,KAAK,CAAA,GAAI,MAAA,KAAW,IAAA,GAAO,MAAA,GAAY,MAAA;AAC9C,MAAA,IAAI,WAAW,IAAA,EAAM,IAAA,EAAA;AACrB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA,IAAI,MAAA,IAAU,aAAA,CAAc,IAAI,CAAA,EAAG;AACjC,QAAA,MAAA,CAAO,KAAK,CAAA,GAAI,MAAA,CAAO,IAAI,CAAA;AAC3B,QAAA,WAAA,CAAY,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAC9B,QAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AACjB,QAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AACf,QAAA,OAAA,GAAU,IAAA;AAAA,MACZ,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAK,CAAA,GAAI,IAAA;AAChB,QAAA,IAAA,EAAA;AAAA,MACF;AAEA,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,GAAU,IAAA;AAEV,IAAA,IAAI,SAAS,MAAA,EAAQ;AAGnB,MAAA,MAAA,CAAO,KAAK,CAAA,GAAI,cAAA,CAAe,MAAA,EAAQ,IAAI,CAAA;AAC3C,MAAA;AAAA,IACF;AAEA,IAAA,MAAA,CAAO,KAAK,IAAI,IAAA,KAAS,QAAA,IAAa,UAAU,aAAA,CAAc,IAAI,IAAK,MAAA,GAAS,IAAA;AAChF,IAAA,WAAA,CAAY,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAC9B,IAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AACnB,IAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,EACjB;AAGA,EAAA,IAAI,KAAA,GAAQ,IAAA;AAEZ,EAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AAC1B,IAAA,KAAA,GACE,OAAO,CAAA,IAAK,QAAA,CAAS,OAAA,EAAS,MAAA,EAAQ,IAAI,GAAA,CAAI,WAAW,CAAC,CAAA,GACtD,eAAe,OAAA,EAAS,KAAA,EAAO,QAAQ,IAAI,CAAA,GAC3C,OAAO,MAAA,CAAO;AAAA,MACZ,KAAA;AAAA,MACA,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,WAAW,CAAA;AAAA,MACjC,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AAAA,MAC9B,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,KAAK;AAAA,KAC3B,CAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAC,QAAQ,KAAA,EAAO,MAAA,EAAQ,cAAc,OAAA,GAAU,YAAA,CAAa,OAAO,CAAA,GAAI,IAAA,EAAI;AACrF;AAWA,SAAS,QAAA,CAAS,OAAA,EAAS,MAAA,EAAQ,QAAA,EAAU;AAC3C,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,CAAO,QAAQ,KAAA,EAAA,EAAS;AAClD,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA,CAAO,KAAK,CAAC,CAAA,EAAG;AAC1C,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,QAAA,CAAS,GAAA,CAAI,MAAA,CAAO,KAAK,CAAC,CAAA,EAAG;AAC/B,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAUA,SAAS,MAAA,CAAO,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO;AACrC,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA;AAChC,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA;AAEpC,EAAA,OAAO,SAAS,IAAA,GAAO,MAAA,KAAW,IAAA,GAAO,MAAA,KAAW,QAAQ,KAAA,KAAU,IAAA;AACxE;AAYA,SAAS,cAAA,CAAe,OAAA,EAAS,KAAA,EAAO,MAAA,EAAQ,IAAA,EAAM;AACpD,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAI;AAEzB,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,GAAA,CAAI,CAAC,OAAO,KAAA,KAAU;AAC3C,IAAA,IAAK,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA,KAAM,QAAQ,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,KAAM,IAAA,IAAS,MAAA,CAAO,OAAA,EAAS,KAAA,EAAO,KAAK,CAAA,EAAG;AACvG,MAAA,OAAO,KAAA;AAAA,IACT;AAGA,IAAA,MAAM,YAAA,GAAe,EAAE,IAAA,KAAS,MAAA,IAAU,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,KAAM,IAAA,IAAQ,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA,KAAM,IAAA,CAAA;AAEtG,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,QAAA,CAAS,GAAA,CAAI,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IAC5B;AAEA,IAAA,OAAO,YAAA;AAAA,EACT,CAAC,CAAA;AAGD,EAAA,MAAM,cAAc,EAAC;AAErB,EAAA,MAAM,UAAU,EAAC;AAEjB,EAAA,MAAM,QAAQ,EAAC;AAEf,EAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,MAAA,CAAO,QAAQ,KAAA,EAAA,EAAS;AAClD,IAAA,IAAI,OAAA,CAAQ,KAAK,CAAA,IAAM,MAAA,CAAO,SAAS,KAAA,EAAO,MAAA,CAAO,KAAK,CAAC,KAAK,QAAA,CAAS,GAAA,CAAI,MAAA,CAAO,KAAK,CAAC,CAAA,EAAI;AAC5F,MAAA,WAAA,CAAY,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAC9B,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAC,CAAA;AACnC,MAAA,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,IACjC;AAAA,EACF;AAEA,EAAA,OAAO,OAAO,MAAA,CAAO;AAAA,IACnB,KAAA;AAAA,IACA,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,WAAW,CAAA;AAAA,IACjC,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AAAA,IAC9B,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,KAAK;AAAA,GAC3B,CAAA;AACH;AASA,SAAS,aAAa,OAAA,EAAS;AAC7B,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAC,KAAA,EAAO,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG,SAAS,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,OAAO,GAAE,CAAA;AACrG;AA3OA,IAAA,mBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,4BAAA,GAAA;AAEA,IAAA,YAAA,EAAA;AACA,IAAA,cAAA,EAAA;AA4DgB,IAAA,MAAA,CAAA,mBAAA,EAAA,qBAAA,CAAA;AAmFP,IAAA,MAAA,CAAA,QAAA,EAAA,UAAA,CAAA;AAsBA,IAAA,MAAA,CAAA,MAAA,EAAA,QAAA,CAAA;AAiBA,IAAA,MAAA,CAAA,cAAA,EAAA,gBAAA,CAAA;AAgDA,IAAA,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACzOT,IAAA,sBAAA,GAAA,EAAA;AAAA,QAAA,CAAA,sBAAA,EAAA;AAAA,EAAA,SAAA,EAAA,MAAA,SAAA;AAAA,EAAA,cAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAqBA,SAAS,QAAA,CAAS,OAAO,MAAA,EAAQ;AAC/B,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,MAAA,IAAU,GAAA;AAAA,EACnB;AAEA,EAAA,MAAM,IAAA,GAAO,OAAO,KAAK,CAAA;AAEzB,EAAA,OAAO,SAAS,IAAA,IAAQ,OAAO,KAAK,MAAA,KAAW,QAAA,GAAW,KAAK,MAAA,GAAS,GAAA;AAC1E;AAQA,SAAS,OAAO,KAAA,EAAO;AACrB,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,OAAO,KAAK,CAAA;AAEzB,EAAA,OAAO,SAAS,IAAA,IAAQ,OAAO,KAAK,IAAA,KAAS,QAAA,GAAW,KAAK,IAAA,GAAO,IAAA;AACtE;AAjDA,IAqEa,SAAA,CAAA,CA2RA;AAhWb,IAAA,mBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,uBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AACA,IAAA,cAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AAiBS,IAAA,MAAA,CAAA,QAAA,EAAA,UAAA,CAAA;AAoBA,IAAA,MAAA,CAAA,MAAA,EAAA,QAAA,CAAA;AA4BF,IAAM,YAAN,MAAgB;AAAA,MArEvB;AAqEuB,QAAA,MAAA,CAAA,IAAA,EAAA,WAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUrB,WAAA,CAAY,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,SAAS,IAAA,EAAM;AAC/C,QAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,QAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AACd,QAAA,IAAA,CAAK,QAAA,GAAW,OAAA;AAChB,QAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAEf,QAAA,MAAA,CAAO,OAAO,IAAI,CAAA;AAAA,MACpB;AAAA;AAAA,MAGA,IAAI,IAAA,GAAO;AACT,QAAA,OAAO,IAAA,CAAK,KAAA;AAAA,MACd;AAAA;AAAA,MAGA,IAAI,MAAA,GAAS;AACX,QAAA,OAAO,KAAK,MAAA,CAAO,MAAA;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,IAAI,KAAA,GAAQ;AACV,QAAA,OAAO,IAAA,CAAK,MAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYA,IAAI,OAAA,GAAU;AACZ,QAAA,OAAO,IAAA,CAAK,QAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,GAAG,GAAA,EAAK;AACN,QAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA,IAAK,MAAM,CAAA,IAAK,GAAA,IAAO,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ;AAClE,UAAA,MAAM,IAAI,mBAAmB,yBAAA,EAA2B;AAAA,YACtD,QAAQ,IAAA,CAAK,KAAA;AAAA,YACb,GAAA;AAAA,YACA,MAAA,EAAQ,KAAK,MAAA,CAAO;AAAA,WACrB,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAE5B,QAAA,OAAO,IAAA,GAAO,CAAA,GAAI,IAAA,GAAO,IAAA,CAAK,SAAS,IAAI,CAAA;AAAA,MAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAaA,OAAO,GAAA,EAAK;AACV,QAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA,IAAK,MAAM,CAAA,IAAK,GAAA,IAAO,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ;AAClE,UAAA,MAAM,IAAI,mBAAmB,yBAAA,EAA2B;AAAA,YACtD,QAAQ,IAAA,CAAK,KAAA;AAAA,YACb,GAAA;AAAA,YACA,MAAA,EAAQ,KAAK,MAAA,CAAO;AAAA,WACrB,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAE5B,QAAA,IAAI,OAAO,CAAA,EAAG;AACZ,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,OAAO,IAAA,CAAK,OAAA,KAAY,IAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA,IAAK,IAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,IAAI,CAAC,CAAA;AAAA,MAChG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,WAAA,GAAc;AACZ,QAAA,IAAI,IAAA,CAAK,YAAY,IAAA,EAAM;AACzB,UAAA,OAAO,KAAK,OAAA,CAAQ,KAAA;AAAA,QACtB;AAEA,QAAA,OAAO,OAAO,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,MAAM,CAAC,CAAA;AAAA,MAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,CAAC,MAAA,CAAO,QAAQ,CAAA,GAAI;AAClB,QAAA,MAAM,QAAQ,IAAA,CAAK,MAAA;AACnB,QAAA,MAAM,UAAU,IAAA,CAAK,QAAA;AACrB,QAAA,IAAI,GAAA,GAAM,CAAA;AAEV,QAAA,OAAO;AAAA,UACL,IAAA,GAAO;AACL,YAAA,IAAI,GAAA,IAAO,MAAM,MAAA,EAAQ;AACvB,cAAA,OAAO,EAAC,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,MAAA,EAAS;AAAA,YACtC;AAEA,YAAA,MAAM,IAAA,GAAO,MAAM,GAAA,EAAK,CAAA;AAExB,YAAA,OAAO,EAAC,MAAM,KAAA,EAAO,KAAA,EAAO,OAAO,CAAA,GAAI,IAAA,GAAO,OAAA,CAAQ,IAAI,CAAA,EAAC;AAAA,UAC7D;AAAA,SACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,OAAA,GAAU;AACR,QAAA,MAAM,GAAA,GAAM,IAAI,KAAA,CAAM,IAAA,CAAK,OAAO,MAAM,CAAA;AAExC,QAAA,KAAA,IAAS,MAAM,CAAA,EAAG,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,QAAQ,GAAA,EAAA,EAAO;AACjD,UAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAC5B,UAAA,GAAA,CAAI,GAAG,CAAA,GAAI,IAAA,GAAO,IAAI,IAAA,GAAO,IAAA,CAAK,SAAS,IAAI,CAAA;AAAA,QACjD;AAEA,QAAA,OAAO,GAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA+BA,cAAA,GAAiB;AACf,QAAA,MAAM,GAAA,GAAM,IAAI,YAAA,CAAa,IAAA,CAAK,SAAS,MAAM,CAAA;AAEjD,QAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,IAAA,CAAK,QAAA,CAAS,QAAQ,KAAA,EAAA,EAAS;AACzD,UAAA,GAAA,CAAI,KAAK,CAAA,GAAI,QAAA,CAAS,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG,IAAA,CAAK,OAAA,EAAS,OAAA,CAAQ,KAAK,CAAA,IAAK,IAAI,CAAA;AAAA,QAClF;AAEA,QAAA,OAAO,GAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,cAAA,CAAe,OAAA,GAAU,EAAC,EAAG;AAC3B,QAAA,MAAM,EAAC,YAAA,GAAe,OAAA,EAAO,GAAI,OAAA;AAEjC,QAAA,IAAI,YAAA,KAAiB,OAAA,IAAW,YAAA,KAAiB,KAAA,EAAO;AACtD,UAAA,MAAM,IAAI,mBAAmB,uCAAA,EAAyC;AAAA,YACpE,QAAQ,IAAA,CAAK,KAAA;AAAA,YACb,QAAA,EAAU;AAAA,WACX,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,GAAA,GAAM,IAAI,YAAA,CAAa,IAAA,CAAK,OAAO,MAAM,CAAA;AAE/C,QAAA,KAAA,IAAS,MAAM,CAAA,EAAG,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,QAAQ,GAAA,EAAA,EAAO;AACjD,UAAA,MAAM,IAAA,GAAO,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA;AAC5B,UAAA,MAAM,QAAQ,IAAA,GAAO,CAAA,GAAI,IAAA,GAAO,IAAA,CAAK,SAAS,IAAI,CAAA;AAElD,UAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,YAAA,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AACX,YAAA;AAAA,UACF;AAGA,UAAA,MAAM,MAAA,GAAS,KAAA,KAAU,IAAA,GAAO,GAAA,GAAM,QAAA,CAAS,KAAA,EAAO,IAAA,CAAK,OAAA,EAAS,OAAA,CAAQ,IAAI,CAAA,IAAK,IAAI,CAAA;AAEzF,UAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA,EAAG;AACzB,YAAA,GAAA,CAAI,GAAG,CAAA,GAAI,MAAA;AACX,YAAA;AAAA,UACF;AAEA,UAAA,IAAI,iBAAiB,OAAA,EAAS;AAC5B,YAAA,MAAM,IAAI,mBAAmB,2CAAA,EAA6C;AAAA,cACxE,QAAQ,IAAA,CAAK,KAAA;AAAA,cACb,GAAA;AAAA,cACA,KAAA;AAAA,cACA,IAAA,EAAM,KAAA,KAAU,IAAA,GAAO,MAAA,GAAS,OAAO,KAAA;AAAA,cACvC,IAAA,EAAM;AAAA,aACP,CAAA;AAAA,UACH;AAEA,UAAA,GAAA,CAAI,GAAG,CAAA,GAAI,GAAA;AAAA,QACb;AAEA,QAAA,OAAO,GAAA;AAAA,MACT;AAAA,KACF;AAwBO,IAAM,iBAAN,MAAqB;AAAA,MAhW5B;AAgW4B,QAAA,MAAA,CAAA,IAAA,EAAA,gBAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAc1B,WAAA,CAAY,EAAC,OAAA,EAAS,YAAA,EAAc,cAAA,EAAgB,eAAe,QAAA,EAAU,QAAA,EAAU,aAAA,EAAe,SAAA,EAAS,EAAG;AAChH,QAAA,IAAA,CAAK,QAAA,GAAW,OAAA;AAChB,QAAA,IAAA,CAAK,aAAA,GAAgB,YAAA;AACrB,QAAA,IAAA,CAAK,eAAA,GAAkB,cAAA;AACvB,QAAA,IAAA,CAAK,iBAAiB,aAAA,IAAiB,IAAA;AACvC,QAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AACjB,QAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AACjB,QAAA,IAAA,CAAK,iBAAiB,aAAA,IAAiB,IAAA;AACvC,QAAA,IAAA,CAAK,UAAA,GAAa,SAAA;AAAA,MACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiCA,aAAa,OAAA,CAAQD,KAAAA,EAAM,OAAA,GAAU,EAAC,EAAG;AACvC,QAAA,MAAM,EAAC,aAAA,EAAAM,cAAAA,EAAa,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,kBAAA,EAAA,EAAA,qBAAA,CAAA,CAAA;AAE9B,QAAA,MAAM,MAAA,GAAS,IAAIA,cAAAA,CAAcN,KAAAA,EAAM;AAAA,UACrC,GAAG,kBAAkB,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA,UAK5B,gBAAA,EAAkB;AAAA,SACnB,CAAA;AAED,QAAA,OAAO,MAAM,MAAA,CAAO,YAAA,CAAa,UAAA,CAAW,OAAO,CAAC,CAAA;AAAA,MACtD;AAAA;AAAA,MAGA,IAAI,OAAA,GAAU;AACZ,QAAA,OAAO,IAAA,CAAK,QAAA;AAAA,MACd;AAAA;AAAA,MAGA,IAAI,QAAA,GAAW;AACb,QAAA,OAAO,IAAA,CAAK,SAAA;AAAA,MACd;AAAA;AAAA,MAGA,IAAI,KAAA,GAAQ;AACV,QAAA,OAAO,CAAC,IAAA,CAAK,SAAA,EAAW,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA,MAC9C;AAAA;AAAA,MAGA,IAAI,QAAA,GAAW;AACb,QAAA,OAAO,IAAA,CAAK,SAAA;AAAA,MACd;AAAA;AAAA,MAGA,IAAI,SAAA,GAAY;AACd,QAAA,OAAO,IAAA,CAAK,UAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,IAAI,aAAA,GAAgB;AAClB,QAAA,OAAO,IAAA,CAAK,cAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,OAAO,IAAA,EAAM;AACX,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAA;AAExC,QAAA,IAAI,UAAU,EAAA,EAAI;AAChB,UAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,QAAA,EAAW,IAAI,CAAA,gBAAA,CAAA,EAAoB;AAAA,YAC9D,MAAA,EAAQ,IAAA;AAAA,YACR,kBAAkB,IAAA,CAAK;AAAA,WACxB,CAAA;AAAA,QACH;AAEA,QAAA,OAAO,IAAI,SAAA;AAAA,UACT,IAAA;AAAA,UACA,IAAA,CAAK,cAAc,KAAK,CAAA;AAAA,UACxB,IAAA,CAAK,gBAAgB,KAAK,CAAA;AAAA,UAC1B,IAAA,CAAK,cAAA,GAAiB,KAAK,CAAA,IAAK;AAAA,SAClC;AAAA,MACF;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACjeA,IAAA,qBAAA,GAAA,EAAA;AAAA,QAAA,CAAA,qBAAA,EAAA;AAAA,EAAA,aAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAkHA,gBAAgB,UAAA,CAAW,MAAA,EAAQ,SAAA,EAAW,MAAA,EAAQ;AACpD,EAAA,IAAI,QAAA,GAAW,CAAA;AAEf,EAAA,WAAS;AACP,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA;AACrC,IAAA,MAAM,EAAC,SAAA,EAAS,GAAI,MAAM,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,CAAA,EAAG,SAAA,EAAW,QAAQ,CAAA,CAAE,KAAA,CAAM,MAAM,CAAA;AAElF,IAAA,IAAI,cAAc,CAAA,EAAG;AACnB,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,SAAA,KAAc,YAAY,MAAA,GAAS,MAAA,CAAO,KAAK,MAAA,CAAO,QAAA,CAAS,CAAA,EAAG,SAAS,CAAC,CAAA;AAClF,IAAA,QAAA,IAAY,SAAA;AAAA,EACd;AACF;AAsBA,eAAe,cAAA,CAAe,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO;AAC/C,EAAA,IAAI,MAAA;AAEJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,MAAMO,GAAAA,CAAI,kBAAA,CAAmB,MAAM,EAAC,aAAA,EAAe,OAAM,CAAA;AAAA,EACpE,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,aAAA;AAAA,MACR,qCAAA;AAAA,MACA;AAAA;AAAA;AAAA,QAGE,MAAA,EAAQ,MAAA;AAAA;AAAA,UAA2B,OAAQ,OAAA,IAAW;AAAA,SAAK,CAAE,KAAA,CAAM,IAAI,CAAA,CAAE,CAAC,CAAA;AAAA,QAC1E,IAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,EAAC,OAAO,KAAA;AAAK,KACf;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,aAAA,CAAc,qCAAA,EAAuC,EAAC,IAAA,EAAM,OAAM,CAAA;AAAA,EAC9E;AAEA,EAAA,OAAO,MAAA;AACT;AAoBA,SAAS,aAAA,CAAc,UAAU,iBAAA,EAAmB;AAClD,EAAA,MAAM,SAAA,GAAY,SAAS,GAAA,CAAI,CAAoB,UAAU,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAC,CAAC,CAAA;AAE3F,EAAA,OAAO,SAAA,CAAU,KAAA,CAAM,CAAC,KAAA,KAAU,MAAA,CAAO,aAAA,CAAc,KAAK,CAAA,IAAK,KAAA,IAAS,CAAC,CAAA,GACvE,IAAA,CAAK,GAAA;AAAA,IACH,iBAAA;AAAA,IACA,UAAU,MAAA,CAAO,CAAC,KAAK,KAAA,KAAU,GAAA,GAAM,OAAO,CAAC;AAAA,GACjD,GACA,iBAAA;AACN;AAaA,SAAS,WAAW,aAAA,EAAe;AACjC,EAAA,OAAO,gBAAgB,CAAA,GAAI,CAAA;AAC7B;AAeA,SAAS,gBAAA,CAAiB,UAAA,EAAY,MAAA,EAAQP,KAAAA,EAAM;AAClD,EAAA,IAAI,UAAA,KAAe,MAAA,IAAa,OAAO,UAAA,KAAe,UAAA,EAAY;AAChE,IAAA,MAAM,IAAI,mBAAmB,+BAAA,EAAiC;AAAA,MAC5D,QAAA,EAAU,UAAA;AAAA,MACV,MAAM,OAAO,UAAA;AAAA,MACb,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,YAAA;AAAA,MACR,IAAA,EAAMA;AAAA,KACP,CAAA;AAAA,EACH;AAKA,EAAA,IAAI,MAAA,KAAW,MAAA,KAAc,OAAO,MAAA,KAAW,QAAA,IAAY,WAAW,IAAA,IAAQ,OAAO,MAAA,CAAO,OAAA,KAAY,SAAA,CAAA,EAAY;AAClH,IAAA,MAAM,IAAI,mBAAmB,+BAAA,EAAiC;AAAA,MAC5D,QAAA,EAAU,MAAA;AAAA,MACV,MAAM,OAAO,MAAA;AAAA,MACb,MAAA,EAAQ,QAAA;AAAA,MACR,MAAA,EAAQ,QAAA;AAAA,MACR,IAAA,EAAMA;AAAA,KACP,CAAA;AAAA,EACH;AACF;AAjQA,IAoDM,eAAA,CAAA,CAMA,eAAA,CAAA,CAUA,mBAAA,CAAA,CAcA,WAAA,CAAA,CAWA,kBAAA,CAAA,CAsKO;AAnQb,IAAA,kBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,sBAAA,GAAA;AAYA,IAAA,iBAAA,EAAA;AACA,IAAA,cAAA,EAAA;AACA,IAAA,iBAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AACA,IAAA,aAAA,EAAA;AACA,IAAA,aAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AACA,IAAA,oBAAA,EAAA;AAaA,IAAA,iBAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AAQA,IAAA,mBAAA,EAAA;AACA,IAAA,kBAAA,EAAA;AAUA,IAAM,eAAA,GAAkB,KAAK,IAAA,GAAO,IAAA;AAMpC,IAAM,eAAA,GAAkB,MAAM,IAAA,GAAO,IAAA;AAUrC,IAAM,mBAAA,GAAsB,KAAA;AAc5B,IAAM,WAAA,GAAc,KAAK,IAAA,GAAO,IAAA;AAWhC,IAAM,kBAAA,GAAqB,KAAA;AAqBX,IAAA,MAAA,CAAA,UAAA,EAAA,YAAA,CAAA;AAqCD,IAAA,MAAA,CAAA,cAAA,EAAA,gBAAA,CAAA;AA4CN,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AAsBA,IAAA,MAAA,CAAA,UAAA,EAAA,YAAA,CAAA;AAiBA,IAAA,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAyBF,IAAM,gBAAN,MAAoB;AAAA,MAnQ3B;AAmQ2B,QAAA,MAAA,CAAA,IAAA,EAAA,eAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgDzB,WAAA,CAAY,QAAA,EAAU,OAAA,GAAU,EAAC,EAAG;AAClC,QAAA,MAAM;AAAA,UACJ,UAAA;AAAA,UACA,kBAAA,GAAqB,GAAA;AAAA,UACrB,wBAAA,GAA2B,KAAK,IAAA,GAAO,IAAA;AAAA,UACvC,UAAA,GAAa,WAAA;AAAA,UACb,gBAAA,GAAmB,IAAA;AAAA,UACnB,MAAA,GAAS,IAAA;AAAA,UACT,KAAA;AAAA,UACA,oBAAA;AAAA,UACA,UAAA;AAAA,UACA;AAAA,SACF,GAAI,OAAA;AACJ,QAAA,IAAA,CAAK,iBAAA,GAAoB,gBAAA;AACzB,QAAA,MAAM,OAAA,GAAU,SAAA,CAAU,QAAA,EAAU,UAAU,CAAA;AAC9C,QAAA,IAAA,CAAK,QAAQ,OAAA,CAAQ,IAAA;AAMrB,QAAA,IAAA,CAAK,cAAc,OAAA,CAAQ,IAAA;AAE3B,QAAA,IAAA,CAAK,MAAA,GAAS,cAAA,CAAe,KAAA,EAAO,IAAA,CAAK,KAAK,CAAA;AAM9C,QAAA,IAAA,CAAK,qBAAA,GAAwB,6BAAA,CAA8B,oBAAA,EAAsB,IAAA,CAAK,KAAK,CAAA;AAC3F,QAAA,IAAA,CAAK,mBAAA,GAAsB,kBAAA;AAC3B,QAAA,IAAA,CAAK,yBAAA,GAA4B,wBAAA;AAEjC,QAAA,IAAI,CAAC,MAAA,CAAO,aAAA,CAAc,UAAU,CAAA,IAAK,cAAc,CAAA,EAAG;AACxD,UAAA,MAAM,IAAI,mBAAmB,uCAAA,EAAyC;AAAA,YACpE,QAAA,EAAU,UAAA;AAAA,YACV,MAAM,OAAO,UAAA;AAAA,YACb,MAAM,IAAA,CAAK;AAAA,WACZ,CAAA;AAAA,QACH;AAGA,QAAA,IAAA,CAAK,WAAA,GAAc,UAAA;AAEnB,QAAA,gBAAA,CAAiB,UAAA,EAAY,MAAA,EAAQ,IAAA,CAAK,KAAK,CAAA;AAG/C,QAAA,IAAA,CAAK,gBAAA,GAAmB,MAAA,KAAW,MAAA,GAAY,IAAA,GAAO,MAAA;AACtD,QAAA,IAAA,CAAK,WAAA,GAAc,UAAA;AACnB,QAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAQf,QAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AAOrB,QAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAEf,QAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAKf,QAAA,IAAA,CAAK,QAAA,GAAW,KAAA;AAShB,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AASpB,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAMpB,QAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,QAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,QAAA,IAAA,CAAK,kBAAA,GAAqB,IAAA;AAC1B,QAAA,IAAA,CAAK,iBAAA,GAAoB,IAAA;AACzB,QAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAYf,QAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAElB,QAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AAKvB,QAAA,IAAA,CAAK,0BAAA,GAA6B,KAAA;AAElC,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAWpB,QAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AAGrB,QAAA,IAAA,CAAK,YAAA,GAAe,CAAA;AAEpB,QAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AAGjB,QAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AAErB,QAAA,IAAA,CAAK,kBAAA,GAAqB,KAAA;AAAA,MAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeA,aAAA,CAAc,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO;AACnC,QAAA,IAAI,KAAK,WAAA,EAAa;AACpB,UAAA,MAAM,OAAA,GAAU,QAAQ,CAAA,GAAI,IAAA,CAAK,MAAO,OAAA,GAAU,KAAA,GAAS,GAAG,CAAA,GAAI,GAAA;AAElE,UAAA,IAAA,CAAK,YAAY,EAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,SAAQ,CAAA;AAAA,QACnD;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYA,eAAA,GAAkB;AAChB,QAAA,IAAI,KAAK,OAAA,EAAS;AAChB,UAAA,IAAA,CAAK,QAAQ,cAAA,EAAe;AAAA,QAC9B;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA8BA,MAAM,SAAA,CAAU,MAAA,GAAS,EAAC,MAAA,EAAQ,CAAA,EAAG,KAAA,EAAO,IAAA,EAAI,EAAG,UAAA,GAAa,KAAA,EAAO,QAAA,GAAW,IAAA,EAAM;AACtF,QAAAC,OAAAA,CAAO,IAAA,CAAK,QAAA,EAAU,yEAAyE,CAAA;AAO/F,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,QAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,QAAA,IAAA,CAAK,YAAA,GAAe,CAAA;AAEpB,QAAA,IAAA,CAAK,eAAA,EAAgB;AACrB,QAAA,IAAA,CAAK,aAAA,CAAc,MAAA,EAAQ,CAAA,EAAG,CAAC,CAAA;AAK/B,QAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,IAAA,CAAK,KAAA,EAAO,MAAM,CAAA;AAOlD,QAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,SAAA,CAAU,IAAA,CAAK,OAAO,IAAA,CAAK,WAAW,CAAA,EAAG,MAAA,EAAQ,MAAM,CAAA;AAExF,QAAA,IAAI,UAAA,EAAY;AACd,UAAA,MAAM,UAAA,CAAW,MAAA,EAAQ,MAAA,EAAQ,MAAM,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,MAAM,CAAC,CAAA;AAC7F,UAAA;AAAA,QACF;AAEA,QAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,QAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAEf,QAAA,IAAI;AACF,UAAA,MAAM,KAAK,SAAA,CAAU,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,UAAU,MAAM,CAAA;AAAA,QAC9D,SAAS,KAAA,EAAO;AACd,UAAA,MAAM,IAAA,CAAK,WAAW,IAAI,CAAA;AAC1B,UAAA,MAAM,KAAA;AAAA,QACR;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBA,UAAA,GAAa;AACX,QAAA,IAAI,KAAK,QAAA,EAAU;AACjB,UAAA,MAAM,IAAI,mBAAmB,iEAAA,EAAmE;AAAA,YAC9F,MAAM,IAAA,CAAK;AAAA,WACZ,CAAA;AAAA,QACH;AAEA,QAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAAA,MAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,MAAM,SAAS,OAAA,EAAS;AACtB,QAAA,IAAI;AACF,UAAA,MAAM,IAAA,CAAK,WAAW,OAAO,CAAA;AAAA,QAC/B,CAAA,SAAE;AACA,UAAA,IAAA,CAAK,QAAA,GAAW,KAAA;AAAA,QAClB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,MAAM,WAAW,OAAA,EAAS;AACxB,QAAA,MAAM,SAAS,IAAA,CAAK,OAAA;AACpB,QAAA,MAAM,SAAS,IAAA,CAAK,OAAA;AAEpB,QAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,QAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAEpB,QAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,KAAW,IAAA,EAAM;AACtC,UAAA;AAAA,QACF;AAEA,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,MAAM,MAAA,CAAO,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM;AAAA,UAAC,CAAC,CAAA;AACnC,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,MAAA,CAAO,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM,CAAA;AAAA,MACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,MAAM,cAAc,IAAA,EAAM;AACxB,QAAA,IAAA,CAAK,UAAA,EAAW;AAEhB,QAAA,IAAI,MAAA;AAEJ,QAAA,IAAI;AACF,UAAA,MAAA,GAAS,MAAM,IAAA,EAAK;AAAA,QACtB,SAAS,KAAA,EAAO;AACd,UAAA,MAAM,IAAA,CAAK,SAAS,IAAI,CAAA;AACxB,UAAA,MAAM,KAAA;AAAA,QACR;AAEA,QAAA,MAAM,IAAA,CAAK,SAAS,KAAK,CAAA;AAEzB,QAAA,OAAO,MAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYA,MAAM,SAAA,CAAU,MAAA,EAAQ,MAAA,EAAQ,UAAA,EAAY,UAAU,MAAA,EAAQ;AAK5D,QAAA,MAAM,gBAAA,GAAmB,QAAA;AACzB,QAAA,MAAM,aAAa,EAAA,GAAK,IAAA;AAGxB,QAAA,MAAM,eAAe,EAAC;AACtB,QAAA,IAAI,WAAA,GAAc,CAAA;AAElB,QAAA,IAAI,IAAA,GAAO,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA;AACzB,QAAA,IAAI,oBAAA,GAAuB,EAAA;AAa3B,QAAA,WAAA,MAAiB,KAAA,IAAS,UAAA,CAAW,MAAA,EAAQ,UAAA,EAAY,MAAM,CAAA,EAAG;AAQhE,UAAA,MAAM,UAAA,GAAa,WAAA;AACnB,UAAA,MAAM,YAAA,GAAe,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,MAAA,CAAO,OAAO,CAAC,IAAA,EAAM,KAAK,CAAC,CAAA,GAAI,KAAA;AACtE,UAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,OAAA,CAAQ,gBAAgB,CAAA;AAE3D,UAAA,YAAA,CAAa,KAAK,KAAK,CAAA;AACvB,UAAA,WAAA,IAAe,KAAA,CAAM,MAAA;AAErB,UAAA,IAAI,kBAAkB,EAAA,EAAI;AAExB,YAAA,oBAAA,GAAuB,UAAA,GAAa,KAAK,MAAA,GAAS,aAAA;AAClD,YAAA;AAAA,UACF;AAGA,UAAA,IAAA,GAAO,MAAA,CAAO,KAAK,YAAA,CAAa,QAAA,CAAS,EAAE,gBAAA,CAAiB,MAAA,GAAS,EAAE,CAAC,CAAA;AAKxE,UAAA,IAAI,cAAc,eAAA,EAAiB;AACjC,YAAA,MAAM,IAAI,iBAAA;AAAA,cACR,CAAA,wDAAA,EAA2D,eAAA,IAAmB,IAAA,GAAO,IAAA,CAAK,CAAA,eAAA,CAAA;AAAA,cAC1F;AAAA,gBACE,MAAM,IAAA,CAAK,KAAA;AAAA,gBACX,aAAA,EAAe,WAAA;AAAA,gBACf,aAAA,EAAe,eAAA;AAAA,gBACf,KAAA,EAAO;AAAA;AACT,aACF;AAAA,UACF;AAAA,QACF;AAEA,QAAA,IAAI,yBAAyB,EAAA,EAAI;AAC/B,UAAA,MAAM,IAAI,iBAAA;AAAA,YACR,0FAAA;AAAA,YACA;AAAA,cACE,MAAM,IAAA,CAAK,KAAA;AAAA,cACX,KAAA,EAAO;AAAA;AACT,WACF;AAAA,QACF;AAEA,QAAA,MAAM,YAAA,GAAe,MAAA,CAAO,MAAA,CAAO,YAAY,CAAA;AAE/C,QAAA,MAAM,cAAA,GAAiB,uBAAuB,gBAAA,CAAiB,MAAA;AAG/D,QAAA,MAAM,YAAY,YAAA,CAAa,QAAA,CAAS,CAAA,EAAG,cAAc,EAAE,QAAA,EAAS;AACpE,QAAA,MAAM,YAAY,MAAM,cAAA,CAAe,SAAA,EAAW,IAAA,CAAK,OAAO,UAAU,CAAA;AACxE,QAAA,MAAM,YAAA,GAAe,uBAAA,CAAwB,SAAA,EAAW,IAAA,CAAK,OAAO,UAAU,CAAA;AAE9E,QAAA,MAAM,iBAAA,GAAoB,cAAA;AAC1B,QAAA,MAAM,oBAAoB,aAAA,CAAc,SAAA,CAAU,gBAAgB,CAAA,CAAE,QAAQ,CAAC,CAAA;AAC7E,QAAA,MAAM,mBAAmB,iBAAA,GAAoB,iBAAA;AAC7C,QAAA,MAAM,aAAa,aAAA,CAAc,SAAA,CAAU,gBAAgB,CAAA,CAAE,gBAAgB,CAAC,CAAA;AAC9E,QAAA,MAAM,YAAY,aAAA,CAAc,SAAA,CAAU,gBAAgB,CAAA,CAAE,aAAa,CAAC,CAAA;AAO1E,QAAA,MAAM,EAAC,IAAA,EAAM,QAAA,EAAU,GAAA,EAAK,GAAA,EAAK,OAAA,EAAO,GAAI,MAAM,MAAA,CAAO,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,CAAA;AAC5E,QAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AAQjB,QAAA,IAAA,CAAK,aAAA,GAAgB,GAAG,GAAG,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,EAAI,OAAO,IAAI,QAAQ,CAAA,CAAA;AAQzD,QAAA,IAAA,CAAK,kBAAA,GAAqB,KAAA;AAS1B,QAAA,MAAM,mBAAA,GAAsB,CAAC,iBAAA,EAAmB,UAAA,EAAY,SAAS,CAAA,CAAE,KAAA;AAAA,UACrE,CAAC,KAAA,KAAU,MAAA,CAAO,aAAA,CAAc,KAAK,KAAK,KAAA,IAAS;AAAA,SACrD;AAEA,QAAA,IAAI,mBAAA,EAAqB;AACvB,UAAA,IAAA,CAAK,kBAAA,GAAqB,cAAA,GAAiB,iBAAA,GAAoB,SAAA,GAAY,UAAA,IAAc,QAAA;AAAA,QAC3F;AAEA,QAAA,IAAI,UAAA,EAAY;AAWd,UAAA,IAAA,CAAK,aAAA,GAAgB,YAAA,CAAa,QAAA,CAAS,CAAA,EAAG,cAAc,CAAA;AAC5D,UAAA,IAAA,CAAK,aAAA,CAAc,MAAA,EAAQ,CAAA,EAAG,CAAC,CAAA;AAC/B,UAAA;AAAA,QACF;AAGA,QAAA,IAAA,CAAK,aAAA,GAAgB,YAAA,CAAa,QAAA,CAAS,CAAA,EAAG,cAAc,CAAA;AAU5D,QAAA,MAAM,WAAW,YAAA,CAAa,YAAA,EAAc,IAAA,CAAK,gBAAA,EAAkB,KAAK,KAAK,CAAA;AAC7E,QAAA,MAAM,cAAc,QAAA,CAAS,MAAA;AAG7B,QAAA,MAAM,cAAc,aAAA,CAAc,IAAA,CAAK,iBAAiB,QAAA,EAAU,YAAY,GAAG,iBAAiB,CAAA;AAClG,QAAA,MAAM,kBAAkB,aAAA,CAAc,IAAA,CAAK,aAAA,CAAc,QAAQ,GAAG,iBAAiB,CAAA;AAIrF,QAAA,MAAM,aAAA,GAAgB,aAAA;AAAA,UACpB,KAAK,gBAAA,CAAiB,QAAA,EAAU,YAAY,CAAA,CAAE,KAAA,CAAM,SAAS,MAAM,CAAA;AAAA,UACnE;AAAA,SACF;AAOA,QAAA,MAAM,QAAA,GAAW,mBAAA,GAAsB,aAAA,CAAc,MAAA,EAAQ,SAAS,IAAI,EAAC,MAAA,EAAQ,CAAA,EAAG,KAAA,EAAO,CAAA,EAAC;AAC9F,QAAA,MAAM,aAAa,QAAA,CAAS,KAAA;AAE5B,QAAA,IAAI,mBAAA,IAAuB,KAAK,kBAAA,EAAoB;AAClD,UAAA,0BAAA;AAAA,YACE,WAAA;AAAA,YACA,UAAA;AAAA,YACA,SAAA;AAAA,YACA,IAAA,CAAK,KAAA;AAAA,YACL,IAAA,CAAK,mBAAA;AAAA,YACL,WAAA;AAAA,YACA,IAAA,CAAK,iBAAA;AAAA,YACL,QAAA;AAAA,YACA,IAAA,CAAK,UAAA;AAAA,cACH,eAAA;AAAA,cACA,UAAA;AAAA,cACA,UAAA;AAAA,cACA,QAAA;AAAA,cACA,IAAA,CAAK,cAAA,CAAe,MAAA,EAAQ,QAAA,EAAU,WAAW,iBAAiB,CAAA;AAAA,cAClE,WAAA,GAAc;AAAA,aAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAOA,eAAA,GACE,UAAA,CAAW,IAAA,CAAK,cAAA,CAAe,MAAA,EAAQ,UAAU,SAAA,EAAW,iBAAiB,CAAC,CAAA,GAAI,UAAA,GAAa,UAAA;AAAA;AAAA;AAAA;AAAA,YAIjG,KAAK,YAAA,KAAiB,IAAA;AAAA,YACtB;AAAA,WACF;AAAA,QACF;AAEA,QAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,IAAK,MAAA,CAAO,UAAU,IAAA,EAAM;AAQhD,UAAA,IAAA,CAAK,aAAA,CAAc,MAAA,EAAQ,CAAA,EAAG,CAAC,CAAA;AAC/B,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,UAAA,GAAa,UAAA;AAqBnB,QAAA,4BAAA,CAA6B,WAAA,EAAa,IAAA,CAAK,KAAA,EAAO,aAAa,CAAA;AASnE,QAAA,kBAAA,CAAmB,UAAA,EAAY,IAAA,CAAK,KAAA,EAAO,UAAU,CAAA;AACrD,QAAA,mBAAA,CAAoB,SAAA,EAAW,IAAA,CAAK,KAAA,EAAO,UAAU,CAAA;AAMrD,QAAA,MAAM,iBAAA,GAAoB,gBAAA,GAAA,CAAoB,QAAA,CAAS,MAAA,GAAS,UAAA,IAAc,UAAA;AAK9E,QAAA,IAAI,oBAAoB,QAAA,EAAU;AAChC,UAAA,MAAM,IAAI,kBAAkB,6CAAA,EAA+C;AAAA,YACzE,MAAM,IAAA,CAAK,KAAA;AAAA,YACX,QAAA;AAAA,YACA,aAAA,EAAe,iBAAA;AAAA,YACf,KAAA,EAAO;AAAA,WACR,CAAA;AAAA,QACH;AAEA,QAAA,IAAA,CAAK,aAAA,CAAc,MAAA,EAAQ,CAAA,EAAG,CAAC,CAAA;AAAA,MACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBA,MAAM,OAAA,CAAQ,MAAA,EAAQ,YAAA,EAAc,SAAA,EAAW,cAAc,aAAA,EAAe;AAC1E,QAAAA,OAAAA,CAAO,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,SAAS,2BAA2B,CAAA;AAEhE,QAAA,MAAM,SAAS,IAAA,CAAK,OAAA;AACpB,QAAA,MAAM,SAAS,IAAA,CAAK,OAAA;AACpB,QAAA,IAAI,IAAA,GAAO,CAAA;AAEX,QAAA,OAAO,OAAO,SAAA,EAAW;AACvB,UAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,eAAA,EAAiB,YAAY,IAAI,CAAA;AAEzD,UAAA,MAAM,EAAC,SAAA,EAAS,GAAI,MAAM,OAAO,IAAA,CAAK,MAAA,EAAQ,YAAA,GAAe,IAAA,EAAM,MAAA,EAAQ,YAAA,GAAe,IAAI,CAAA,CAAE,MAAM,MAAM,CAAA;AAE5G,UAAA,IAAI,cAAc,CAAA,EAAG;AACnB,YAAA,MAAM,IAAI,kBAAkB,gDAAA,EAAkD;AAAA,cAC5E,MAAM,IAAA,CAAK,KAAA;AAAA,cACX,UAAU,IAAA,CAAK,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAMf,SAAA,EAAW,IAAA;AAAA,cACX,cAAc,YAAA,GAAe,IAAA;AAAA,cAC7B,aAAA;AAAA,cACA,KAAA,EAAO;AAAA,aACR,CAAA;AAAA,UACH;AAEA,UAAA,IAAA,IAAQ,SAAA;AAAA,QACV;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,YAAA,CAAa,WAAA,EAAa,IAAA,EAAM,UAAA,EAAY;AAC1C,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,aAAA,CAAc,IAAI,CAAA,IAAK,MAAA,CAAO,aAAA,CAAc,UAAU,CAAA,IAAK,IAAA,GAAO,CAAA,IAAK,UAAA,GAAa,CAAA;AAE1G,QAAA,OAAO,eAAe,MAAA,GAAS,IAAA,CAAK,cAAc,IAAA,EAAM,UAAU,IAAI,UAAA,GAAa,CAAA,CAAA;AAAA,MACrF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeA,aAAA,CAAc,UAAU,UAAA,EAAY;AAClC,QAAA,OAAO,KAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,UAAU,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,WAAA,GAAc,KAAK,GAAA,CAAI,CAAA,EAAG,UAAU,CAAC,CAAC,CAAC,CAAA;AAAA,MAC/F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAuBA,WAAW,WAAA,EAAa,UAAA,EAAY,YAAY,QAAA,EAAU,aAAA,EAAe,mBAAmB,IAAA,EAAM;AAChG,QAAA,OAAO;AAAA,UACL,IAAA,EAAM,IAAA,CAAK,YAAA,CAAa,WAAA,EAAa,IAAA,CAAK,eAAe,UAAA,EAAY,QAAA,EAAU,aAAa,CAAA,EAAG,UAAU,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAKzG,YAAA,EACE,gBAAA,KAAqB,IAAA,GACjB,IAAA,GACA,IAAA,CAAK,YAAA,CAAa,gBAAA,EAAkB,IAAA,CAAK,cAAA,CAAe,UAAA,EAAY,QAAA,EAAU,aAAa,GAAG,UAAU,CAAA;AAAA;AAAA;AAAA,UAG9G,OAAA,0BAAU,IAAA,KAAS,IAAA,CAAK,aAAa,WAAA,EAAa,IAAA,EAAM,UAAU,CAAA,EAAzD,SAAA,CAAA;AAAA;AAAA;AAAA,UAGT,0BAAU,MAAA,CAAA,CAAC,IAAA,KACT,IAAA,CAAK,YAAA,CAAa,aAAa,IAAA,CAAK,cAAA,CAAe,UAAA,EAAY,EAAC,MAAM,QAAA,EAAU,CAAA,IAAI,aAAa,CAAA,EAAG,UAAU,CAAA,EADtG,UAAA;AAAA,SAEZ;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiCA,iBAAA,CAAkB,MAAA,EAAQ,QAAA,EAAU,SAAA,EAAW,iBAAA,EAAmB;AAChE,QAAA,OACE,QAAA,CAAS,KAAA,GAAQ,SAAA,KAChB,MAAA,CAAO,KAAA,KAAU,QAAQ,MAAA,CAAO,MAAA,GAAS,CAAA,CAAA,IAC1C,iBAAA,GAAoB,IAAA,CAAK,yBAAA;AAAA,MAE7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,cAAA,CAAe,UAAA,EAAY,QAAA,EAAU,aAAA,EAAe;AAClD,QAAA,MAAM,YACJ,QAAA,KAAa,IAAA,GAAO,UAAA,GAAa,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,OAAO,IAAA,CAAK,GAAA,CAAI,GAAG,QAAA,CAAS,QAAQ,CAAC,CAAC,CAAA;AAEzG,QAAA,OAAO,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,UAAA,EAAY,SAAS,CAAA,GAAI,SAAA;AAAA,MAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBA,gBAAA,CAAiB,UAAU,GAAA,EAAK;AAC9B,QAAA,IAAI,KAAK,YAAA,KAAiB,IAAA,IAAQ,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA,EAAG;AAC9D,UAAA,OAAO,QAAA;AAAA,QACT;AAEA,QAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,CAAoB,KAAA,KAAU,KAAA,CAAM,WAAW,CAAC,CAAC,CAAA;AACpF,QAAA,MAAM,SAAS,GAAA,CAAI,MAAA;AAAA,UACjB,CAAoB,KAAA,KAClB,CAAC,KAAA,CAAM,GAAA,CAAI,MAAM,WAAW,CAAC,CAAA,IAAK,IAAA,CAAK,iBAAiB,IAAA,IAAQ,IAAA,CAAK,aAAa,GAAA,CAAI,KAAA,CAAM,WAAW,CAAC;AAAA,SAC5G;AAEA,QAAA,OAAO,CAAC,GAAG,QAAA,EAAU,GAAG,MAAM,CAAA;AAAA,MAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBA,cAAc,QAAA,EAAU;AACtB,QAAA,IAAI,KAAK,YAAA,KAAiB,IAAA,IAAQ,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA,EAAG;AAC9D,UAAA,OAAO,QAAA;AAAA,QACT;AAEA,QAAA,OAAO,QAAA,CAAS,MAAA;AAAA,UACd,CAAoB,KAAA,KAAU,IAAA,CAAK,YAAA,KAAiB,IAAA,IAAQ,CAAC,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,WAAW,CAAC;AAAA,SACvG;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBA,WAAA,GAAc;AACZ,QAAA,IAAA,CAAK,YAAA,uBAAmB,GAAA,EAAI;AAAA,MAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBA,kBAAkB,MAAA,EAAQ;AACxB,QAAA,IAAI,WAAW,MAAA,EAAW;AACxB,UAAA,IAAA,CAAK,gBAAA,GAAmB,MAAA;AAAA,QAC1B;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBA,gBAAgB,EAAC,UAAA,EAAY,MAAA,EAAM,GAAI,EAAC,EAAG;AAKzC,QAAA,gBAAA,CAAiB,UAAA,EAAY,MAAA,EAAQ,IAAA,CAAK,KAAK,CAAA;AAE/C,QAAA,IAAA,CAAK,WAAA,GAAc,UAAA;AACnB,QAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,MACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,cAAA,CAAe,MAAA,EAAQ,QAAA,EAAU,SAAA,EAAW,iBAAA,EAAmB;AAC7D,QAAA,OAAO,IAAA,CAAK,iBAAiB,IAAA,IAAQ,IAAA,CAAK,kBAAkB,MAAA,EAAQ,QAAA,EAAU,WAAW,iBAAiB,CAAA;AAAA,MAC5G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBA,yBAAA,GAA4B;AAC1B,QAAA,IAAI,KAAK,YAAA,KAAiB,IAAA,IAAQ,IAAA,CAAK,YAAA,CAAa,SAAS,CAAA,EAAG;AAC9D,UAAA;AAAA,QACF;AAEA,QAAA,IAAI,IAAA,CAAK,UAAA,KAAe,IAAA,CAAK,gBAAA,EAAiB,EAAG;AAC/C,UAAA,IAAA,CAAK,YAAA,uBAAmB,GAAA,EAAI;AAC5B,UAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAAA,QACpB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,gBAAA,GAAmB;AACjB,QAAAA,OAAAA,CAAO,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,YAAY,0CAA0C,CAAA;AAElF,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,gBAAgB,CAAA;AAE5C,QAAA,OAAO;AAAA;AAAA,UAEL,IAAA,CAAK,aAAA;AAAA,UACL,OAAO,eAAe,CAAA;AAAA,UACtB,OAAO,aAAa,CAAA;AAAA,UACpB,OAAO,QAAQ,CAAA;AAAA,UACf,GAAG,KAAK,UAAA,CAAW,GAAA;AAAA,YACjB,CAAoB,KAAA,KAClB,CAAA,EAAG,KAAA,CAAM,WAAW,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,QAAQ,CAAC,IAAI,KAAA,CAAM,QAAQ,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,aAAa,CAAC,CAAA;AAAA;AACvF,SACF,CAAE,KAAK,GAAG,CAAA;AAAA,MACZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,SAAA,GAAY;AACV,QAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,QAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAAA,MACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAcA,kBAAA,GAAqB;AACnB,QAAAA,OAAAA;AAAA,UACE,KAAK,kBAAA,KAAuB,IAAA,IAAQ,KAAK,iBAAA,KAAsB,IAAA,IAAQ,KAAK,SAAA,KAAc,IAAA;AAAA,UAC1F;AAAA,SACF;AAEA,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,iBAAA,GAAoB,IAAA,CAAK,kBAAA;AAE/C,QAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,UAAU,IAAA,CAAK,SAAA,GAAY,IAAA,CAAK,kBAAkB,CAAC,CAAA;AAAA,MACjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAyBA,eAAA,GAAkB;AAChB,QAAA,IAAI,IAAA,CAAK,iBAAiB,IAAA,EAAM;AAC9B,UAAA,OAAO,IAAA,CAAK,YAAA;AAAA,QACd;AAEA,QAAAA,OAAAA,CAAO,IAAA,CAAK,eAAA,EAAiB,4EAA4E,CAAA;AAEzG,QAAA,MAAM,WAAA,GAAc,KAAK,kBAAA,EAAmB;AAC5C,QAAA,MAAM,MAAA,GAAS,KAAK,eAAA,CAAgB,MAAA;AAAA,UAClC,CAAoB,KAAA,KAAU,IAAA,CAAK,YAAA,KAAiB,IAAA,IAAQ,CAAC,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,WAAW,CAAC;AAAA,SACvG;AACA,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,CAAoB,KAAA,KAAU;AACrD,UAAA,qBAAA,CAAsB,KAAA,EAAO,WAAA,EAAa,IAAA,CAAK,KAAK,CAAA;AAEpD,UAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAC,CAAA;AAE3C,UAAA,OAAO,EAAC,OAAO,KAAA,EAAO,GAAA,EAAK,QAAQ,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAC,CAAA,EAAC;AAAA,QACnE,CAAC,CAAA;AAGD,QAAA,MAAM,SAAS,EAAC;AAEhB,QAAA,MAAM,OAAA,uBAAc,GAAA,EAAI;AAExB,QAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,GAAG,KAAK,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE,KAAK,CAAA,EAAG;AAC/D,UAAA,MAAM,IAAA,GAAO,MAAA,CAAO,EAAA,CAAG,EAAE,CAAA;AAGzB,UAAA,MAAM,QACJ,IAAA,KAAS,MAAA,IAAa,KAAK,KAAA,IAAS,IAAA,CAAK,MACrC,IAAA,GACA,EAAC,KAAA,EAAO,IAAA,CAAK,OAAO,GAAA,EAAK,IAAA,CAAK,KAAK,MAAA,EAAQ,CAAA,EAAG,QAAQ,IAAA,EAAI;AAEhE,UAAA,IAAI,UAAU,IAAA,EAAM;AAClB,YAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,UACnB;AAEA,UAAA,KAAA,CAAM,MAAM,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,GAAA,EAAK,KAAK,GAAG,CAAA;AACxC,UAAA,KAAA,CAAM,MAAA,IAAU,CAAA;AAChB,UAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,KAAA,EAAO,EAAC,KAAA,EAAO,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI,CAAA;AAAA,QACnE;AAEA,QAAA,IAAA,CAAK,YAAA,GAAe,EAAC,MAAA,EAAQ,OAAA,EAAO;AAEpC,QAAA,OAAO,IAAA,CAAK,YAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAaA,MAAM,cAAc,KAAA,EAAO;AACzB,QAAAA,OAAAA;AAAA,UACE,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,kBAAA,KAAuB,IAAA;AAAA,UAC5C;AAAA,SACF;AAEA,QAAA,MAAM,OAAO,IAAA,CAAK,eAAA,EAAgB,CAAE,OAAA,CAAQ,IAAI,KAAK,CAAA;AAErD,QAAAA,OAAAA,CAAO,MAAM,sDAAsD,CAAA;AAEnE,QAAA,MAAM,EAAC,OAAK,GAAI,IAAA;AAEhB,QAAA,IAAI,KAAA,CAAM,WAAW,IAAA,EAAM;AACzB,UAAA,MAAM,MAAA,GAAS,KAAA,CAAM,GAAA,GAAM,KAAA,CAAM,KAAA;AAOjC,UAAA,uBAAA,CAAwB,MAAA,EAAQ,IAAA,CAAK,KAAA,EAAO,aAAA,CAAc,IAAA,CAAK,QAAQ,gBAAgB,CAAA,CAAE,aAAa,CAAC,CAAC,CAAA;AAIxG,UAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA;AAClC,UAAA,MAAM,IAAA,GAAO,IAAA,CAAK,kBAAA,GAAqB,KAAA,CAAM,KAAA;AAE7C,UAAA,MAAM,KAAK,OAAA,CAAQ,MAAA,EAAQ,GAAG,MAAA,EAAQ,IAAA,EAAM,OAAO,MAAM,CAAA;AAEzD,UAAA,KAAA,CAAM,MAAA,GAAS,MAAA;AAAA,QACjB;AAEA,QAAA,OAAO,EAAC,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ,KAAA,EAAO,KAAK,KAAA,GAAQ,KAAA,CAAM,KAAA,EAAO,GAAA,EAAK,KAAK,GAAA,GAAM,KAAA,CAAM,KAAA,EAAO,IAAA,EAAM,MAAM,KAAA,EAAK;AAAA,MAC/G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYA,mBAAmB,KAAA,EAAO;AACxB,QAAA,MAAM,OAAO,IAAA,CAAK,eAAA,EAAgB,CAAE,OAAA,CAAQ,IAAI,KAAK,CAAA;AAErD,QAAAA,OAAAA,CAAO,MAAM,sDAAsD,CAAA;AAEnE,QAAA,IAAA,CAAK,MAAM,MAAA,IAAU,CAAA;AAErB,QAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG;AAC3B,UAAA,IAAA,CAAK,MAAM,MAAA,GAAS,IAAA;AAAA,QACtB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeA,MAAM,aAAA,CAAc,QAAA,EAAU,QAAA,EAAU,YAAY,KAAA,EAAO;AACzD,QAAA,IAAI,aAAa,CAAA,EAAG;AAClB,UAAA;AAAA,QACF;AAEA,QAAAA,OAAAA,CAAO,IAAA,CAAK,iBAAA,KAAsB,IAAA,EAAM,uEAAuE,CAAA;AAE/G,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,UAAU,CAAA;AACzD,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,SAAA,GAAY,UAAU,CAAA;AACjD,QAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,iBAAA,GAAA,CAAqB,QAAA,GAAW,QAAA,IAAY,UAAA;AAEvE,QAAA,KAAA,IAAS,IAAA,GAAO,CAAA,EAAG,IAAA,GAAO,QAAA,EAAU,QAAQ,SAAA,EAAW;AACrD,UAAA,IAAA,CAAK,eAAA,EAAgB;AAErB,UAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,WAAW,IAAI,CAAA;AACjD,UAAA,MAAM,OAAA,GAAU,KAAA,CAAM,QAAA,CAAS,CAAA,EAAG,QAAQ,UAAU,CAAA;AAEpD,UAAA,MAAM,IAAA,CAAK,OAAA;AAAA,YACT,OAAA;AAAA,YACA,CAAA;AAAA,YACA,OAAA,CAAQ,MAAA;AAAA,YACR,IAAA,CAAK,iBAAA,GAAA,CAAqB,QAAA,GAAW,IAAA,IAAQ,UAAA;AAAA,YAC7C;AAAA,WACF;AACA,UAAA,MAAM,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM,KAAK,CAAA;AAAA,QAClC;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,YAAA,GAAe;AACnB,QAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACvB,UAAA,MAAM,IAAI,iBAAA;AAAA,YACR,qFAAA;AAAA,YACA;AAAA,cACE,MAAM,IAAA,CAAK,KAAA;AAAA,cACX,KAAA,EAAO;AAAA;AACT,WACF;AAAA,QACF;AAEA,QAAA,MAAM,gBAAA,GAAmB,QAAA;AAEzB,QAAA,MAAM,gBAAA,GAAmB,CAAA;AACzB,QAAA,MAAM,oBAAA,GAAuB,IAAA,CAAK,aAAA,CAAc,OAAA,CAAQ,kBAAkB,gBAAgB,CAAA;AAK1F,QAAA,IAAI,yBAAyB,EAAA,EAAI;AAC/B,UAAA,MAAM,IAAI,iBAAA;AAAA,YACR,0FAAA;AAAA,YACA;AAAA,cACE,MAAM,IAAA,CAAK,KAAA;AAAA,cACX,KAAA,EAAO;AAAA;AACT,WACF;AAAA,QACF;AAEA,QAAA,MAAM,cAAA,GAAiB,uBAAuB,gBAAA,CAAiB,MAAA;AAC/D,QAAA,MAAM,YAAA,GAAe,IAAA,CAAK,aAAA,CAAc,QAAA,CAAS,kBAAkB,cAAc,CAAA;AA6CjF,QAAA,IAAA,CAAK,0BAAA,GAA6B,KAAA;AAElC,QAAA,IAAA,CAAK,OAAA,GAAU,MAAM,cAAA,CAAe,YAAA,CAAa,UAAS,EAAG,IAAA,CAAK,OAAO,aAAa,CAAA;AAItF,QAAA,MAAM,YAAY,uBAAA,CAAwB,IAAA,CAAK,OAAA,EAAS,IAAA,CAAK,OAAO,aAAa,CAAA;AAMjF,QAAA,IAAA,CAAK,aAAA,GAAgB,gBAAA;AACrB,QAAA,IAAA,CAAK,kBAAA,GAAqB,cAAA;AAC1B,QAAA,IAAA,CAAK,iBAAA,GAAoB,KAAK,kBAAA,GAAqB,aAAA,CAAc,KAAK,OAAA,CAAQ,gBAAgB,CAAA,CAAE,QAAQ,CAAC,CAAA;AAazG,QAAA,IAAA,CAAK,UAAA,GAAa,SAAA;AAClB,QAAA,IAAA,CAAK,kBAAkB,YAAA,CAAa,IAAA,CAAK,YAAY,IAAA,CAAK,gBAAA,EAAkB,KAAK,KAAK,CAAA;AAAA,MACxF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,eAAA,CAAgB,QAAQ,KAAA,EAAO;AAC7B,QAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,CAAC,KAAK,OAAA,IAAW,CAAC,IAAA,CAAK,iBAAA,IAAqB,CAAC,IAAA,CAAK,eAAA,IAAmB,CAAC,KAAK,UAAA,EAAY;AAC1G,UAAA,MAAM,IAAI,iBAAA;AAAA,YACR,qFAAA;AAAA,YACA;AAAA,cACE,MAAM,IAAA,CAAK,KAAA;AAAA,cACX;AAAA;AACF,WACF;AAAA,QACF;AAEA,QAAA,MAAM,YAAY,IAAA,CAAK,UAAA;AACvB,QAAA,MAAM,SAAS,IAAA,CAAK,eAAA;AAGpB,QAAA,MAAM,aAAa,aAAA,CAAc,IAAA,CAAK,QAAQ,gBAAgB,CAAA,CAAE,gBAAgB,CAAC,CAAA;AACjF,QAAA,MAAM,YAAY,aAAA,CAAc,IAAA,CAAK,QAAQ,gBAAgB,CAAA,CAAE,aAAa,CAAC,CAAA;AAC7E,QAAA,MAAM,mBAAmB,aAAA,CAAc,IAAA,CAAK,QAAQ,gBAAgB,CAAA,CAAE,QAAQ,CAAC,CAAA;AAM/E,QAAA,MAAM,EAAC,QAAQ,QAAA,EAAU,KAAA,EAAO,YAAU,GAAI,aAAA,CAAc,QAAQ,SAAS,CAAA;AAE7E,QAAAA,OAAAA,CAAO,IAAA,CAAK,SAAA,KAAc,IAAA,EAAM,qEAAqE,CAAA;AAKrG,QAAA,0BAAA;AAAA,UACE,UAAA;AAAA,UACA,SAAA;AAAA,UACA,gBAAA;AAAA,UACA,IAAA,CAAK,iBAAA;AAAA,UACL,IAAA,CAAK,SAAA;AAAA,UACL,UAAA;AAAA,UACA,IAAA,CAAK,KAAA;AAAA,UACL,IAAA,CAAK,SAAA;AAAA,UACL,QAAA;AAAA,UACA;AAAA,SACF;AAgBA,QAAA,IAAI,CAAC,KAAK,0BAAA,EAA4B;AACpC,UAAA,KAAA,MAAW,SAAS,SAAA,EAAW;AAC7B,YAAA,wBAAA,CAAyB,KAAA,EAAO,UAAA,EAAY,IAAA,CAAK,KAAK,CAAA;AAAA,UACxD;AAIA,UAAA,iBAAA,CAAkB,SAAA,EAAW,KAAK,KAAK,CAAA;AAEvC,UAAA,IAAA,CAAK,0BAAA,GAA6B,IAAA;AAAA,QACpC;AAWA,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,iBAAA,GAAA,CAAqB,QAAA,GAAW,UAAA,IAAc,UAAA;AACrE,QAAAA,OAAAA;AAAA,UACE,UAAA,KAAe,CAAA,IAAK,UAAA,KAAe,CAAA,IAAK,aAAa,IAAA,CAAK,SAAA;AAAA,UAC1D,oCAAoC,SAAS,CAAA,cAAA,EAAiB,IAAA,CAAK,SAAS,SACnE,UAAU,CAAA,2BAAA;AAAA,SACrB;AAEA,QAAA,OAAO,EAAC,MAAA,EAAQ,UAAA,EAAY,SAAA,EAAW,YAAY,QAAA,EAAQ;AAAA,MAC7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeA,MAAM,8BAA8B,MAAA,EAAQ;AAC1C,QAAA,MAAM,EAAC,QAAQ,UAAA,EAAY,UAAA,EAAY,UAAQ,GAAI,IAAA,CAAK,eAAA,CAAgB,MAAA,EAAQ,8BAA8B,CAAA;AAe9G,QAAA,MAAM,cAAc,EAAC;AAerB,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,UAAA,EAAY,mBAAmB,CAAA;AAC1D,QAAA,MAAM,MAAA,GAAS,IAAI,UAAA,CAAW,SAAS,CAAA;AAIvC,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,CAAoB,KAAA,KAAU;AACrD,UAAA,MAAM,MAAA,uBAAa,GAAA,EAAI;AACvB,UAAA,WAAA,CAAY,KAAK,MAAM,CAAA;AAsBvB,UAAA,MAAM,MAAA,GAAS,aAAA,CAAc,KAAA,CAAM,QAAQ,CAAC,CAAA;AAE5C,UAAA,OAAO;AAAA,YACL,KAAA;AAAA,YACA,MAAA;AAAA,YACA,SAAA,EAAW,aAAA,CAAc,KAAA,CAAM,WAAW,CAAC,CAAA;AAAA,YAC3C,QAAA,EAAU,aAAA,CAAc,KAAA,CAAM,UAAU,CAAC,CAAA;AAAA,YACzC,IAAA,EAAM,aAAA,CAAc,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,YACjC,UAAA,EAAY,MAAA,CAAO,aAAA,CAAc,MAAM,CAAA,IAAK,MAAA,IAAU,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA,GAAI,QAAA;AAAA,YAClF,OAAA,EAAS;AAAA,WACX;AAAA,QACF,CAAC,CAAA;AAED,QAAA,MAAM,IAAA,CAAK,cAAc,QAAA,EAAU,UAAA,EAAY,YAAY,OAAO,OAAA,EAAS,MAAM,WAAA,KAAgB;AAC/F,UAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,WAAA,EAAa,SAAS,SAAA,EAAW;AAC3D,YAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,cAAc,KAAK,CAAA;AAErD,YAAA,KAAA,MAAW,SAAS,KAAA,EAAO;AAIzB,cAAA,iBAAA;AAAA,gBACE,UAAU,CAAA,GAAI,OAAA,GAAU,OAAA,CAAQ,QAAA,CAAS,QAAQ,UAAU,CAAA;AAAA,gBAC3D,UAAA;AAAA,gBACA,KAAA;AAAA,gBACA,KAAA,CAAM,SAAA;AAAA,gBACN,KAAA,CAAM,QAAA;AAAA,gBACN,KAAA,CAAM,IAAA;AAAA,gBACN;AAAA,eACF;AAEA,cAAA,KAAA,IAAS,GAAA,GAAM,CAAA,EAAG,GAAA,GAAM,KAAA,EAAO,GAAA,EAAA,EAAO;AAGpC,gBAAA,IAAI,MAAA,CAAO,GAAG,CAAA,IAAK,CAAA,IAAK,OAAO,GAAG,CAAA,GAAI,MAAM,UAAA,EAAY;AACtD,kBAAA,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,gBAC9B;AAAA,cACF;AAIA,cAAA,IAAI,CAAC,KAAA,CAAM,OAAA,IAAW,KAAA,CAAM,MAAA,CAAO,OAAO,kBAAA,EAAoB;AAC5D,gBAAA,KAAA,CAAM,OAAA,GAAU,IAAA;AAChB,gBAAA,KAAA,CAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,UAAA,EAAY,MAAM,IAAA,CAAK,kBAAA,CAAmB,KAAA,CAAM,KAAK,CAAC,CAAA;AAExF,gBAAA,KAAA,MAAW,KAAA,IAAS,MAAM,MAAA,EAAQ;AAChC,kBAAA,IAAI,KAAA,IAAS,MAAM,UAAA,EAAY;AAC7B,oBAAA,KAAA,CAAM,MAAA,CAAO,OAAO,KAAK,CAAA;AAAA,kBAC3B;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAIA,UAAA,IAAA,CAAK,aAAA,CAAc,iBAAA,EAAmB,IAAA,GAAO,WAAA,EAAa,UAAU,CAAA;AAAA,QACtE,CAAC,CAAA;AAED,QAAA,IAAI,eAAe,CAAA,EAAG;AACpB,UAAA,IAAA,CAAK,aAAA,CAAc,iBAAA,EAAmB,CAAA,EAAG,CAAC,CAAA;AAAA,QAC5C;AAEA,QAAA,OAAO,WAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,MAAM,mBAAmB,KAAA,EAAO;AAC9B,QAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,KAAK,CAAA;AAE3C,QAAA,OAAO,iBAAA;AAAA,UACL,IAAA,CAAK,MAAA;AAAA,UACL,IAAA,CAAK,KAAA;AAAA,UACL,IAAA,CAAK,GAAA;AAAA,UACL,aAAA,CAAc,KAAA,CAAM,aAAa,CAAC,CAAA;AAAA,UAClC,MAAM,WAAW,CAAA;AAAA,UACjB,IAAA,CAAK,KAAA;AAAA,UACL,IAAA,CAAK;AAAA,SACP;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,MAAM,iBAAA,CAAkB,aAAA,GAAgB,MAAM,UAAA,GAAa,CAAA,EAAG,WAAW,IAAA,EAAM;AAC7E,QAAA,IACE,CAAC,IAAA,CAAK,OAAA,IACN,CAAC,IAAA,CAAK,WACN,CAAC,IAAA,CAAK,kBAAA,IACN,CAAC,KAAK,iBAAA,IACN,CAAC,KAAK,eAAA,IACN,CAAC,KAAK,UAAA,EACN;AACA,UAAA,MAAM,IAAI,iBAAA;AAAA,YACR,qFAAA;AAAA,YACA;AAAA,cACE,MAAM,IAAA,CAAK,KAAA;AAAA,cACX,KAAA,EAAO;AAAA;AACT,WACF;AAAA,QACF;AAEA,QAAA,MAAM,YAAY,IAAA,CAAK,UAAA;AACvB,QAAA,MAAM,SAAS,IAAA,CAAK,eAAA;AAOpB,QAAA,IAAA,CAAK,yBAAA,EAA0B;AAgB/B,QAAA,MAAM,eAAA,GAAkB,KAAK,kBAAA,EAAmB;AAChD,QAAA,MAAM,IAAA,GAAO,KAAK,eAAA,EAAgB;AAKlC,QAAA,MAAM,eAAA,GAAkB,IAAA,CAAK,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAK,KAAA,KAAU,GAAA,IAAO,KAAA,CAAM,GAAA,GAAM,KAAA,CAAM,KAAA,CAAA,EAAQ,CAAC,CAAA;AAC7F,QAAA,MAAM,aAAA,GAAgB,aAAA,CAAc,IAAA,CAAK,gBAAA,CAAiB,MAAA,EAAQ,SAAS,CAAA,CAAE,KAAA,CAAM,MAAA,CAAO,MAAM,CAAA,EAAG,eAAe,CAAA;AAClH,QAAA,MAAM,cAAc,eAAA,GAAkB,aAAA;AACtC,QAAA,MAAM,YAAY,aAAA,CAAc,IAAA,CAAK,QAAQ,gBAAgB,CAAA,CAAE,aAAa,CAAC,CAAA;AAC7E,QAAA,MAAM,aAAa,aAAA,CAAc,IAAA,CAAK,QAAQ,gBAAgB,CAAA,CAAE,gBAAgB,CAAC,CAAA;AAKjF,QAAA,uBAAA,CAAwB,WAAA,EAAa,IAAA,CAAK,KAAA,EAAO,SAAS,CAAA;AAU1D,QAAA,IAAI,KAAK,kBAAA,EAAoB;AAC3B,UAAA,0BAAA;AAAA,YACE,WAAA;AAAA,YACA,UAAA;AAAA,YACA,SAAA;AAAA,YACA,IAAA,CAAK,KAAA;AAAA,YACL,IAAA,CAAK,mBAAA;AAAA,YACL,MAAA,CAAO,MAAA;AAAA,YACP,IAAA,CAAK,iBAAA;AAAA,YACL,QAAA;AAAA,YACA,IAAA,CAAK,WAAW,eAAA,EAAiB,UAAA,EAAY,YAAY,QAAA,EAAU,KAAA,EAAO,cAAc,aAAa,CAAA;AAAA;AAAA;AAAA,YAGrG,eAAA,GAAkB,UAAA,CAAW,aAAA,KAAkB,IAAI,IAAI,UAAA,GAAa,UAAA;AAAA,YACpE,KAAK,YAAA,KAAiB,IAAA;AAAA,YACtB;AAAA,WACF;AAAA,QACF;AAIA,QAAA,oBAAA;AAAA,UACE,WAAA;AAAA,UACA,UAAA;AAAA,UACA,SAAA;AAAA,UACA,MAAA,CAAO,MAAA;AAAA,UACP,IAAA,CAAK,iBAAA;AAAA,UACL,KAAK,YAAA,KAAiB;AAAA,SACxB;AAiBA,QAAA,KAAA,MAAW,SAAS,SAAA,EAAW;AAC7B,UAAA,qBAAA,CAAsB,KAAA,EAAO,eAAA,EAAiB,IAAA,CAAK,KAAK,CAAA;AAAA,QAC1D;AAEA,QAAA,mBAAA,CAAoB,SAAA,EAAW,KAAK,KAAK,CAAA;AAUzC,QAAA,MAAM,cAAc,EAAC;AAErB,QAAA,KAAA,MAAW,CAAC,QAAA,EAAU,KAAK,CAAA,IAAK,MAAA,CAAO,SAAQ,EAAG;AAChD,UAAA,IAAA,CAAK,eAAA,EAAgB;AAUrB,UAAA,MAAM,SAAS,IAAA,CAAK,YAAA,EAAc,GAAA,CAAI,KAAA,CAAM,WAAW,CAAC,CAAA;AAExD,UAAA,IAAI,MAAA,EAAQ;AACV,YAAA,WAAA,CAAY,KAAK,MAAM,CAAA;AACvB,YAAA,IAAA,CAAK,aAAA,CAAc,cAAA,EAAgB,QAAA,GAAW,CAAA,EAAG,OAAO,MAAM,CAAA;AAC9D,YAAA;AAAA,UACF;AAEA,UAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,aAAA,CAAc,KAAK,CAAA;AAC3C,UAAA,MAAM,MAAA,GAAS,iBAAA;AAAA,YACb,IAAA,CAAK,MAAA;AAAA,YACL,IAAA,CAAK,KAAA;AAAA,YACL,IAAA,CAAK,GAAA;AAAA;AAAA;AAAA;AAAA,YAIL,aAAA,CAAc,KAAA,CAAM,aAAa,CAAC,CAAA;AAAA;AAAA;AAAA,YAGlC,aAAA,GAAgB,aAAA,CAAc,QAAQ,CAAA,GAAI,IAAA;AAAA,YAC1C,MAAM,WAAW,CAAA;AAAA,YACjB,IAAA,CAAK,KAAA;AAAA,YACL,MAAA;AAAA,YACA,IAAA,CAAK;AAAA,WACP;AAEA,UAAA,WAAA,CAAY,KAAK,MAAM,CAAA;AAEvB,UAAA,IAAI,IAAA,CAAK,YAAA,IAAgB,aAAA,KAAkB,IAAA,EAAM;AAC/C,YAAA,IAAI,IAAA,CAAK,YAAA,CAAa,IAAA,KAAS,CAAA,EAAG;AAChC,cAAA,IAAA,CAAK,UAAA,GAAa,KAAK,gBAAA,EAAiB;AAAA,YAC1C;AAEA,YAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,WAAW,GAAG,MAAM,CAAA;AAAA,UAClD;AAEA,UAAA,IAAA,CAAK,mBAAmB,KAAK,CAAA;AAC7B,UAAA,IAAA,CAAK,aAAA,CAAc,cAAA,EAAgB,QAAA,GAAW,CAAA,EAAG,OAAO,MAAM,CAAA;AAAA,QAChE;AAEA,QAAA,IAAA,CAAK,YAAA,GAAe,WAAA;AAAA,MACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmCA,MAAM,iBAAiB,MAAA,EAAQ,YAAA,GAAe,GAAG,aAAA,GAAgB,IAAA,EAAM,OAAO,IAAA,EAAM;AAClF,QAAA,MAAM,EAAC,QAAQ,UAAA,EAAY,UAAA,EAAY,UAAQ,GAAI,IAAA,CAAK,eAAA,CAAgB,MAAA,EAAQ,iBAAiB,CAAA;AAMjG,QAAA,MAAM,aAAA,GAAgB,YAAA;AACtB,QAAA,MAAM,YAAA,GAAe,aAAA,KAAkB,IAAA,GAAO,UAAA,GAAa,aAAA;AAI3D,QAAAA,OAAAA,CAAO,IAAA,CAAK,YAAA,EAAc,gDAAgD,CAAA;AAC1E,QAAA,MAAM,cAAc,IAAA,CAAK,YAAA;AAEzB,QAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,CAAoB,OAA6B,QAAA,MAAc;AAAA,UACzF,SAAA,EAAW,aAAA,CAAc,KAAA,CAAM,WAAW,CAAC,CAAA;AAAA,UAC3C,QAAA,EAAU,aAAA,CAAc,KAAA,CAAM,UAAU,CAAC,CAAA;AAAA,UACzC,IAAA,EAAM,aAAA,CAAc,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,UACjC,WAAA,EAAa,WAAA,CAAY,QAAQ,CAAA,CAAE,OAAA,CAAQ,MAAA;AAAA,UAC3C,IAAA,EAAM,MAAM,WAAW;AAAA,SACzB,CAAE,CAAA;AAMF,QAAA,MAAM,UACJ,IAAA,KAAS,IAAA,GAAO,OAAO,GAAA,CAAI,MAAM,IAAI,UAAA,CAAW,UAAU,CAAC,CAAA,GAAI,IAAA,CAAK,IAAI,CAAC,KAAA,KAAU,MAAM,QAAA,CAAS,CAAA,EAAG,UAAU,CAAC,CAAA;AAOlH,QAAA,MAAM,IAAA,CAAK,cAAc,QAAA,EAAU,UAAA,EAAY,YAAY,CAAC,OAAA,EAAS,MAAM,KAAA,KAAU;AACnF,UAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,EAAS,QAAA,KAAa;AACtC,YAAA,iBAAA;AAAA,cACE,OAAA;AAAA,cACA,UAAA;AAAA,cACA,KAAA;AAAA,cACA,OAAA,CAAQ,SAAA;AAAA,cACR,OAAA,CAAQ,QAAA;AAAA,cACR,OAAA,CAAQ,IAAA;AAAA,cACR,QAAQ,QAAQ,CAAA,CAAE,QAAA,CAAS,IAAA,EAAM,OAAO,KAAK,CAAA;AAAA,cAC7C,EAAC,WAAA,EAAa,OAAA,CAAQ,WAAA,EAAa,KAAA,EAAO,OAAA,CAAQ,IAAA,EAAM,IAAA,EAAM,IAAA,CAAK,KAAA,EAAO,QAAA,EAAU,QAAA,GAAW,IAAA;AAAI,aACrG;AAAA,UACF,CAAC,CAAA;AAGD,UAAA,IAAA,CAAK,aAAA,CAAc,aAAA,EAAe,aAAA,GAAgB,IAAA,GAAO,OAAO,YAAY,CAAA;AAAA,QAC9E,CAAC,CAAA;AAED,QAAA,IAAI,eAAe,CAAA,EAAG;AACpB,UAAA,IAAA,CAAK,aAAA,CAAc,aAAA,EAAe,aAAA,EAAe,YAAY,CAAA;AAAA,QAC/D;AAIA,QAAA,IAAA,CAAK,aAAA,GAAgB,OAAA;AACrB,QAAA,IAAA,CAAK,YAAA,GAAe,UAAA;AAAA,MACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBA,MAAM,YAAA,GAAe;AAOnB,QAAA,OAAO,MAAM,IAAA,CAAK,aAAA,CAAc,YAAY;AAC1C,UAAA,MAAM,IAAA,CAAK,UAAU,EAAC,MAAA,EAAQ,GAAG,KAAA,EAAO,IAAA,IAAO,IAAI,CAAA;AAEnD,UAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,CAAA,EAAG,CAAC,CAAA;AACjC,UAAA,MAAM,KAAK,YAAA,EAAa;AACxB,UAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,CAAA,EAAG,CAAC,CAAA;AACjC,UAAA,IAAA,CAAK,eAAA,EAAgB;AAErB,UAAA,OAAO,KAAK,cAAA,EAAe;AAAA,QAC7B,CAAC,CAAA;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,cAAA,GAAiB;AACf,QAAAA,OAAAA,CAAO,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,YAAY,0CAA0C,CAAA;AAElF,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,gBAAgB,CAAA;AAI5C,QAAA,MAAM,OAAA,GAAU,KAAK,UAAA,CAAW,GAAA,CAAI,CAAoB,KAAA,KAAU,KAAA,CAAM,WAAW,CAAC,CAAA;AACpF,QAAA,MAAM,QAAA,GAAW,aAAA,CAAc,MAAA,CAAO,aAAa,CAAC,CAAA;AAKpD,QAAA,mBAAA,CAAoB,QAAA,EAAU,IAAA,CAAK,KAAA,EAAO,cAAc,CAAA;AAKxD,QAAA,MAAM,QAAQ,IAAI,YAAA,CAAa,EAAC,EAAG,SAAS,MAAA,EAAQ;AAAA,UAClD,gBAAA,EAAkB,aAAA,CAAc,MAAA,CAAO,QAAQ,CAAC,CAAA;AAAA,UAChD,SAAA,EAAW,QAAA;AAAA,UACX,UAAA,EAAY,CAAA;AAAA,UACZ,eAAA,EAAiB,KAAA;AAAA,UACjB,WAAA,EAAa;AAAA,SACd,CAAA;AAED,QAAA,OAAO;AAAA,UACL,OAAA;AAAA,UACA,QAAA;AAAA,UACA,aAAa,OAAA,CAAQ,MAAA;AAAA,UACrB,MAAA,EAAQ,QAAQ,GAAA,CAAI,CAAuB,SAAS,KAAA,CAAM,gBAAA,CAAiB,IAAI,CAAC,CAAA;AAAA,UAChF,cAAc,KAAA,CAAM,YAAA;AAAA,UACpB,QAAA,EAAU;AAAA,SACZ;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBA,MAAM,UAAU,SAAA,EAAW,EAAC,YAAY,IAAA,EAAI,GAAI,EAAC,EAAG;AAIlD,QAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,SAAA,EAAW,IAAA,CAAK,KAAK,CAAA;AAEpD,QAAA,OAAO,MAAM,IAAA,CAAK,aAAA,CAAc,YAAY;AAC1C,UAAA,MAAM,KAAK,mBAAA,EAAoB;AAE/B,UAAA,OAAO,IAAA,CAAK,WAAA,CAAY,MAAA,EAAQ,EAAC,WAAU,CAAA;AAAA,QAC7C,CAAC,CAAA;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,MAAM,eAAA,GAAkB;AACtB,QAAA,OAAO,MAAM,IAAA,CAAK,aAAA,CAAc,YAAY,MAAM,IAAA,CAAK,qBAAqB,CAAA;AAAA,MAC9E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,MAAM,mBAAA,GAAsB;AAC1B,QAAA,MAAM,IAAA,CAAK,UAAU,EAAC,MAAA,EAAQ,GAAG,KAAA,EAAO,IAAA,IAAO,IAAI,CAAA;AAInD,QAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,CAAA,EAAG,CAAC,CAAA;AACjC,QAAA,MAAM,KAAK,YAAA,EAAa;AACxB,QAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,CAAA,EAAG,CAAC,CAAA;AACjC,QAAA,IAAA,CAAK,eAAA,EAAgB;AAErB,QAAAA,OAAAA;AAAA,UACE,KAAK,OAAA,IAAW,IAAA,CAAK,mBAAmB,IAAA,CAAK,UAAA,IAAc,KAAK,kBAAA,KAAuB,IAAA;AAAA,UACvF;AAAA,SACF;AAEA,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,gBAAgB,CAAA;AAC5C,QAAA,MAAM,SAAA,GAAY,aAAA,CAAc,MAAA,CAAO,aAAa,CAAC,CAAA;AACrD,QAAA,MAAM,UAAA,GAAa,aAAA,CAAc,MAAA,CAAO,gBAAgB,CAAC,CAAA;AACzD,QAAA,MAAM,iBAAA,GAAoB,aAAA,CAAc,MAAA,CAAO,QAAQ,CAAC,CAAA;AAYxD,QAAA,kBAAA,CAAmB,UAAA,EAAY,IAAA,CAAK,KAAA,EAAO,WAAW,CAAA;AACtD,QAAA,mBAAA,CAAoB,SAAA,EAAW,IAAA,CAAK,KAAA,EAAO,WAAW,CAAA;AAKtD,QAAA,IAAI,CAAC,KAAK,kBAAA,EAAoB;AAC5B,UAAA,MAAM,IAAI,kBAAkB,6CAAA,EAA+C;AAAA,YACzE,MAAM,IAAA,CAAK,KAAA;AAAA,YACX,UAAU,IAAA,CAAK,SAAA;AAAA,YACf,aAAA,EAAe,IAAA,CAAK,kBAAA,GAAqB,iBAAA,GAAoB,SAAA,GAAY,UAAA;AAAA,YACzE,KAAA,EAAO;AAAA,WACR,CAAA;AAAA,QACH;AAWA,QAAA,MAAM,WAAA,GAAc,KAAK,kBAAA,EAAmB;AAE5C,QAAA,KAAA,MAAW,KAAA,IAAS,KAAK,UAAA,EAAY;AACnC,UAAA,qBAAA,CAAsB,KAAA,EAAO,WAAA,EAAa,IAAA,CAAK,KAAK,CAAA;AACpD,UAAA,wBAAA,CAAyB,KAAA,EAAO,UAAA,EAAY,IAAA,CAAK,KAAK,CAAA;AAAA,QACxD;AAEA,QAAA,mBAAA,CAAoB,IAAA,CAAK,UAAA,EAAY,IAAA,CAAK,KAAK,CAAA;AAAA,MACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBA,WAAA,CACE,MAAA,EACA,EAAC,SAAA,GAAY,MAAM,MAAA,GAAS,MAAA,EAAW,gBAAA,GAAmB,MAAA,EAAW,SAAS,IAAA,CAAK,YAAA,KAAiB,IAAA,EAAI,GAAI,EAAC,EAC7G;AACA,QAAAA,OAAAA,CAAO,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,YAAY,0CAA0C,CAAA;AAElF,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,gBAAgB,CAAA;AAC5C,QAAA,MAAM,SAAA,GAAY,aAAA,CAAc,MAAA,CAAO,aAAa,CAAC,CAAA;AACrD,QAAA,MAAM,UAAA,GAAa,aAAA,CAAc,MAAA,CAAO,gBAAgB,CAAC,CAAA;AACzD,QAAA,MAAM,iBAAA,GAAoB,aAAA,CAAc,MAAA,CAAO,QAAQ,CAAC,CAAA;AACxD,QAAA,MAAM,MAAA,GAAS,gBAAA,KAAqB,MAAA,GAAY,IAAA,CAAK,iBAAA,GAAoB,gBAAA;AAIzE,QAAA,MAAM,QAAA,GAAW,YAAA,CAAa,IAAA,CAAK,UAAA,EAAY,MAAA,KAAW,SAAY,IAAA,CAAK,gBAAA,GAAmB,MAAA,EAAQ,IAAA,CAAK,KAAK,CAAA;AAEhH,QAAA,MAAM,QAAA,GAAW,aAAA,CAAc,MAAA,EAAQ,SAAS,CAAA;AAKhD,QAAA,MAAM,aAAa,QAAA,CAAS,KAAA;AAC5B,QAAA,MAAM,QAAA,GAAW,cAAc,IAAA,GAAO,IAAA,GAAO,EAAC,IAAA,EAAM,SAAA,GAAY,CAAA,EAAG,QAAA,EAAU,CAAA,EAAC;AAY9E,QAAA,MAAM,aAAA,GAAgB,SAAS,KAAA,GAAQ,IAAA,CAAK,kBAAkB,MAAA,EAAQ,QAAA,EAAU,WAAW,iBAAiB,CAAA;AAK5G,QAAA,MAAM,WAAW,eAAA,EAAgB;AAEjC,QAAA,MAAM,GAAA,mBAAM,MAAA,CAAA,CAAoB,KAAA,EAAkC,IAAA,KAAS;AAGzE,UAAA,MAAM,OAAO,MAAA,GAAS,IAAA,CAAK,iBAAiB,KAAA,EAAO,IAAA,CAAK,UAAU,CAAA,GAAI,KAAA;AACtE,UAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,IAAA,EAAM,iBAAiB,CAAA;AACnD,UAAA,MAAM,IAAA,GAAO,cAAc,MAAA,GAAS,IAAA,CAAK,cAAc,KAAK,CAAA,GAAI,OAAO,iBAAiB,CAAA;AACxF,UAAA,MAAM,QAAA,GAAW,SAAS,aAAA,CAAc,IAAA,CAAK,MAAM,KAAA,CAAM,MAAM,CAAA,EAAG,iBAAiB,CAAA,GAAI,CAAA;AAEvF,UAAA,OAAO,WAAA,CAAY;AAAA,YACjB,QAAA;AAAA,YACA,eAAA,EAAiB,KAAA;AAAA,YACjB,OAAA,EAAS,IAAA;AAAA,YACT,SAAA;AAAA,YACA,cAAc,IAAA,CAAK,mBAAA;AAAA,YACnB,aAAa,KAAA,CAAM,MAAA;AAAA,YACnB,gBAAA,EAAkB,MAAA;AAAA,YAClB,IAAA,EAAM,QAAA;AAAA;AAAA,YAEN,YAAA,EAAc,MAAA;AAAA,YACd,aAAA,EAAe,QAAA;AAAA,YACf,SAAA,EAAW,KAAK,UAAA,CAAW,IAAA,EAAM,MAAM,UAAA,EAAY,QAAA,EAAU,aAAA,EAAe,KAAA,GAAQ,QAAQ,CAAA;AAAA;AAAA;AAAA;AAAA,YAI5F,SAAA,EAAW,IAAA,GAAO,UAAA,CAAW,aAAa,IAAI,UAAA,GAAa;AAAA,WAC5D,CAAA;AAAA,QACH,CAAA,EA1BY,KAAA,CAAA;AA4BZ,QAAA,MAAM,MAAA,GAAS,GAAA,CAAI,QAAA,EAAU,UAAU,CAAA;AAMvC,QAAA,IAAI,CAAC,MAAA,CAAO,IAAA,IAAQ,QAAA,CAAS,SAAS,CAAA,EAAG;AACvC,UAAA,MAAM,MAAA,GAAS,CAAC,GAAG,QAAQ,CAAA,CAAE,IAAA;AAAA,YAC3B,CAAoB,CAAA,EAAsB,CAAA,KAAM,aAAA,CAAc,CAAA,CAAE,QAAQ,CAAC,CAAA,GAAI,aAAA,CAAc,CAAA,CAAE,QAAQ,CAAC;AAAA,WACxG;AAEA,UAAA,KAAA,IAAS,OAAO,QAAA,CAAS,MAAA,GAAS,GAAG,IAAA,IAAQ,CAAA,EAAG,QAAQ,CAAA,EAAG;AACzD,YAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA;AAElC,YAAA,IAAI,GAAA,CAAI,KAAA,EAAO,UAAU,CAAA,CAAE,IAAA,EAAM;AAC/B,cAAA,MAAA,CAAO,YAAY,IAAA,CAAK;AAAA,gBACtB,MAAA,EAAQ,QAAA;AAAA,gBACR,OAAO,KAAA,CAAM,GAAA,CAAI,CAAoB,KAAA,KAAU,KAAA,CAAM,WAAW,CAAC;AAAA,eAClE,CAAA;AACD,cAAA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAEA,QAAA,OAAO,MAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAaA,MAAM,IAAA,CAAK,MAAA,GAAS,IAAA,EAAM;AACxB,QAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,MAAA,EAAQ,IAAA,CAAK,KAAK,CAAA;AAE/C,QAAA,OAAO,MAAM,IAAA,CAAK,aAAA,CAAc,YAAY;AAC1C,UAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA;AAEzC,UAAA,MAAM,IAAA,CAAK,iBAAiB,EAAC,MAAA,EAAQ,SAAS,MAAA,EAAQ,KAAA,EAAO,QAAA,CAAS,aAAA,EAAc,CAAA;AAEpF,UAAA,MAAM,OAAO,IAAA,CAAK,UAAA,CAAW,SAAS,eAAA,EAAiB,CAAA,EAAG,SAAS,aAAa,CAAA;AAEhF,UAAA,OAAO,IAAI,YAAA;AAAA,YACT,IAAA;AAAA,YACA,QAAA,CAAS,OAAA;AAAA,YACT,QAAA,CAAS,QAAA;AAAA,YACT;AAAA,cACE,GAAG,QAAA,CAAS,SAAA;AAAA,cACZ,YAAY,IAAA,CAAK;AAAA,aACnB;AAAA,YACA,QAAA,CAAS;AAAA,WACX;AAAA,QACF,CAAC,CAAA;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBA,MAAM,YAAA,CAAa,MAAA,GAAS,IAAA,EAAM;AAChC,QAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,MAAA,EAAQ,IAAA,CAAK,KAAK,CAAA;AAE/C,QAAA,OAAO,MAAM,IAAA,CAAK,aAAA,CAAc,YAAY;AAC1C,UAAA,MAAM,WAAW,MAAM,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,MAAM,IAAI,CAAA;AAErD,UAAA,MAAM,IAAA,CAAK,iBAAiB,EAAC,MAAA,EAAQ,SAAS,MAAA,EAAQ,KAAA,EAAO,QAAA,CAAS,aAAA,EAAc,CAAA;AAOpF,UAAA,MAAM,EAAC,cAAA,EAAAO,eAAAA,EAAc,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,mBAAA,EAAA,EAAA,sBAAA,CAAA,CAAA;AAE/B,UAAAP,OAAAA,CAAO,IAAA,CAAK,aAAA,EAAe,+CAA+C,CAAA;AAE1E,UAAA,OAAO,IAAIO,eAAAA,CAAe;AAAA,YACxB,SAAS,QAAA,CAAS,OAAA;AAAA,YAClB,cAAc,IAAA,CAAK,aAAA;AAAA,YACnB,gBAAgB,QAAA,CAAS,eAAA;AAAA,YACzB,eAAe,QAAA,CAAS,aAAA;AAAA,YACxB,UAAU,IAAA,CAAK,YAAA;AAAA,YACf,UAAU,QAAA,CAAS,QAAA;AAAA,YACnB,eAAe,QAAA,CAAS,aAAA;AAAA,YACxB,WAAW,EAAC,GAAG,SAAS,SAAA,EAAW,UAAA,EAAY,KAAK,YAAA;AAAY,WACjE,CAAA;AAAA,QACH,CAAC,CAAA;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA2BA,OAAO,WAAA,CAAY,MAAA,EAAQ,SAAA,EAAW;AACpC,QAAA,gBAAA,CAAiB,SAAA,EAAW,KAAK,KAAK,CAAA;AAsBtC,QAAA,MAAM,WAAW,EAAC,IAAA,EAAM,SAAA,GAAY,CAAA,EAAG,UAAU,CAAA,EAAC;AAElD,QAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,MAAA,EAAQ,IAAA,CAAK,KAAK,CAAA;AAQ/C,QAAA,IAAA,CAAK,UAAA,EAAW;AAEhB,QAAA,IAAI,OAAA,GAAU,KAAA;AAEd,QAAA,IAAI;AACF,UAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,QAAA,CAAS,MAAM,QAAQ,CAAA;AAMnD,UAAA,IAAI,QAAA,CAAS,kBAAkB,CAAA,EAAG;AAChC,YAAA,IAAA,CAAK,eAAA,CAAgB,EAAC,MAAA,EAAQ,QAAA,CAAS,QAAQ,KAAA,EAAO,CAAA,IAAI,iBAAiB,CAAA;AAC3E,YAAA;AAAA,UACF;AAOA,UAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,IAAI,UAAA,CAAW,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,QAAA,CAAS,aAAa,CAAC,CAAC,CAAA;AAEpG,UAAA,KAAA,IAAS,OAAO,CAAA,EAAG,IAAA,GAAO,QAAA,CAAS,aAAA,EAAe,QAAQ,SAAA,EAAW;AACnE,YAAA,IAAA,CAAK,eAAA,EAAgB;AAErB,YAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,QAAA,CAAS,gBAAgB,IAAI,CAAA;AAC/D,YAAA,MAAM,MAAA,GAAS,SAAS,MAAA,GAAS,IAAA;AAEjC,YAAA,MAAM,IAAA,CAAK,gBAAA,CAAiB,EAAC,MAAA,EAAQ,KAAA,EAAO,OAAK,EAAG,IAAA,EAAM,QAAA,CAAS,aAAA,EAAe,KAAK,CAAA;AAEvF,YAAA,MAAM,OAAO,IAAA,CAAK,UAAA,CAAW,SAAS,eAAA,EAAiB,IAAA,EAAM,SAAS,aAAa,CAAA;AAGnF,YAAA,MAAM,IAAI,YAAA;AAAA,cACR,IAAA;AAAA,cACA,QAAA,CAAS,OAAA;AAAA,cACT,QAAA,CAAS,QAAA;AAAA,cACT;AAAA,gBACE,GAAG,QAAA,CAAS,SAAA;AAAA,gBACZ,MAAA;AAAA,gBACA,YAAY,IAAA,CAAK;AAAA,eACnB;AAAA,cACA,QAAA,CAAS;AAAA,aACX;AAAA,UACF;AAAA,QACF,SAAS,KAAA,EAAO;AACd,UAAA,OAAA,GAAU,IAAA;AACV,UAAA,MAAM,KAAA;AAAA,QACR,CAAA,SAAE;AACA,UAAA,MAAM,IAAA,CAAK,SAAS,OAAO,CAAA;AAAA,QAC7B;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA0BA,MAAM,QAAA,CAAS,MAAA,EAAQ,QAAA,GAAW,IAAA,EAAM,aAAa,KAAA,EAAO;AAC1D,QAAA,IAAA,CAAK,eAAA,EAAgB;AAErB,QAAA,MAAM,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAA;AAE5C,QAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,CAAA,EAAG,CAAC,CAAA;AACjC,QAAA,MAAM,KAAK,YAAA,EAAa;AACxB,QAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,CAAA,EAAG,CAAC,CAAA;AACjC,QAAA,IAAA,CAAK,eAAA,EAAgB;AAErB,QAAAP,OAAAA,CAAO,IAAA,CAAK,OAAA,EAAS,0CAA0C,CAAA;AAE/D,QAAA,MAAM,YAAY,aAAA,CAAc,IAAA,CAAK,QAAQ,gBAAgB,CAAA,CAAE,aAAa,CAAC,CAAA;AAC7E,QAAA,MAAM,oBAAoB,aAAA,CAAc,IAAA,CAAK,QAAQ,gBAAgB,CAAA,CAAE,QAAQ,CAAC,CAAA;AAIhF,QAAA,MAAM,QAAA,GAAW,aAAA,CAAc,MAAA,EAAQ,SAAS,CAAA;AAChD,QAAA,MAAM,gBAAgB,QAAA,CAAS,KAAA;AAI/B,QAAA,IAAI,aAAA,GAAgB,IAAA;AACpB,QAAA,IAAI,WAAA,GAAc,IAAA;AAOlB,QAAA,IAAI,KAAK,cAAA,CAAe,MAAA,EAAQ,QAAA,EAAU,SAAA,EAAW,iBAAiB,CAAA,EAAG;AAEvE,UAAA,aAAA,GAAgB,MAAM,KAAK,6BAAA,CAA8B,EAAC,QAAQ,QAAA,CAAS,MAAA,EAAQ,KAAA,EAAO,aAAA,EAAc,CAAA;AAOxG,UAAA,WAAA,GAAc,aAAA,CAAc,OAAO,CAAC,GAAA,EAAK,QAAQ,GAAA,GAAM,GAAA,CAAI,MAAM,CAAC,CAAA;AAAA,QACpE;AAGA,QAAA,MAAM,IAAA,CAAK,iBAAA,CAAkB,aAAA,EAAe,aAAA,EAAe,QAAQ,CAAA;AAEnE,QAAAA,OAAAA,CAAO,IAAA,CAAK,YAAA,EAAc,gDAAgD,CAAA;AAC1E,QAAA,IAAA,CAAK,eAAA,EAAgB;AAErB,QAAAA,OAAAA,CAAO,IAAA,CAAK,eAAA,EAAiB,6CAA6C,CAAA;AAgB1E,QAAA,MAAM,kBAAkB,EAAC;AAEzB,QAAA,MAAM,gBAAgB,EAAC;AAEvB,QAAA,MAAM,UAAU,EAAC;AAEjB,QAAA,IAAA,CAAK,YAAA,CAAa,OAAA,CAAQ,CAAC,OAAA,EAAS,QAAA,KAAa;AAC/C,UAAA,MAAM,EAAC,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAM,GAAI,mBAAA;AAAA,YAC9B,OAAA;AAAA;AAAA,YAEA,IAAA,CAAK,eAAA,CAAgB,QAAQ,CAAA,CAAE,WAAW,CAAA;AAAA,YAC1C,IAAA,CAAK,MAAA;AAAA,YACL,IAAA,CAAK,qBAAA;AAAA,YACL;AAAA,WACF;AAEA,UAAA,eAAA,CAAgB,KAAK,MAAM,CAAA;AAC3B,UAAA,aAAA,CAAc,KAAK,MAAM,CAAA;AAEzB,UAAA,IAAI,UAAU,IAAA,EAAM;AAClB,YAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,UACpB;AAAA,QACF,CAAC,CAAA;AAED,QAAA,MAAM,OAAA,GAAU,KAAK,eAAA,CAAgB,GAAA,CAAI,CAAoB,KAAA,KAAU,KAAA,CAAM,WAAW,CAAC,CAAA;AASzF,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,gBAAgB,CAAA;AAK9C,QAAA,MAAM,gBAAgB,OAAA,CAAQ,MAAA,GAAS,CAAA,GAAI,kBAAA,CAAmB,OAAO,CAAA,GAAI,IAAA;AAEzE,QAAA,IAAI,kBAAkB,IAAA,EAAM;AAC1B,UAAA,mBAAA,CAAoB,UAAU,aAAa,CAAA;AAAA,QAC7C;AAGA,QAAA,MAAM,SAAA,GAAY;AAAA,UAChB,gBAAA,EAAkB,iBAAA;AAAA,UAClB,SAAA;AAAA,UACA,UAAA,EAAY,CAAA;AAAA,UACZ,QAAQ,QAAA,CAAS,MAAA;AAAA,UACjB,iBAAiB,aAAA,KAAkB,IAAA;AAAA,UACnC;AAAA,SACF;AAEA,QAAA,OAAO;AAAA,UACL,OAAA;AAAA,UACA,QAAA;AAAA,UACA,SAAA;AAAA,UACA,eAAA;AAAA,UACA,aAAA;AAAA,UACA,aAAA;AAAA,UACA,aAAA;AAAA,UACA,QAAQ,QAAA,CAAS;AAAA,SACnB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,UAAA,CAAW,eAAA,EAAiB,YAAA,EAAc,aAAA,EAAe;AACvD,QAAAA,OAAAA,CAAO,IAAA,CAAK,aAAA,EAAe,+CAA+C,CAAA;AAE1E,QAAA,MAAM,eAAe,IAAA,CAAK,aAAA;AAC1B,QAAA,MAAM,aAAa,YAAA,CAAa,MAAA;AAChC,QAAA,MAAM,WAAW,IAAA,CAAK,YAAA;AACtB,QAAA,MAAM,IAAA,GAAO,IAAI,KAAA,CAAM,QAAQ,CAAA;AAK/B,QAAA,MAAM,cAAA,GAAiB,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,aAAA,GAAgB,GAAG,CAAC,CAAA;AAElE,QAAA,KAAA,IAAS,GAAA,GAAM,CAAA,EAAG,GAAA,GAAM,QAAA,EAAU,GAAA,EAAA,EAAO;AACvC,UAAA,MAAM,MAAA,GAAS,IAAI,KAAA,CAAM,UAAU,CAAA;AAEnC,UAAA,KAAA,IAAS,KAAA,GAAQ,CAAA,EAAG,KAAA,GAAQ,UAAA,EAAY,KAAA,EAAA,EAAS;AAC/C,YAAA,MAAM,WAAA,GAAc,YAAA,CAAa,KAAK,CAAA,CAAE,GAAG,CAAA;AAK3C,YAAA,MAAA,CAAO,KAAK,IAAI,WAAA,GAAc,CAAA,GAAI,OAAO,eAAA,CAAgB,KAAK,EAAE,WAAW,CAAA;AAAA,UAC7E;AAEA,UAAA,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA;AAEZ,UAAA,IAAA,CAAK,eAAe,GAAA,GAAM,CAAA,IAAK,mBAAmB,CAAA,IAAK,GAAA,GAAM,MAAM,QAAA,EAAU;AAC3E,YAAA,IAAA,CAAK,eAAA,EAAgB;AACrB,YAAA,IAAA,CAAK,aAAA,CAAc,MAAA,EAAQ,YAAA,GAAe,GAAA,GAAM,GAAG,aAAa,CAAA;AAAA,UAClE;AAAA,QACF;AAEA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACh2FA,IAAA,eAAA,GAAA,EAAA;AAAA,QAAA,CAAA,eAAA,EAAA;AAAA,EAAA,OAAA,EAAA,MAAA;AAAA,CAAA,CAAA;AAAA,IAoCa;AApCb,IAAA,YAAA,GAAA,KAAA,CAAA;AAAA,EAAA,gBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AAiCO,IAAM,UAAN,MAAc;AAAA,MApCrB;AAoCqB,QAAA,MAAA,CAAA,IAAA,EAAA,SAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUnB,WAAA,CAAY,MAAA,EAAQ,QAAA,EAAU,OAAA,EAAS;AACrC,QAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,QAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AACjB,QAAA,IAAA,CAAK,QAAA,GAAW,OAAA;AAChB,QAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AASf,QAAA,IAAA,CAAK,KAAA,GAAQ,QAAQ,OAAA,EAAQ;AAQ7B,QAAA,IAAA,CAAK,QAAA,GAAW,EAAC,IAAA,EAAM,IAAA,EAAM,SAAS,IAAA,EAAI;AAAA,MAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,IAAI,QAAA,GAAW;AACb,QAAA,OAAO,IAAA,CAAK,SAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,IAAI,MAAA,GAAS;AACX,QAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,KAAA,CAAM,OAAA,GAAU,EAAC,EAAG;AAClB,QAAA,IAAA,CAAK,kBAAkB,OAAO,CAAA;AAE9B,QAAA,MAAM,EAAC,EAAA,GAAK,MAAA,EAAQ,SAAA,GAAY,MAAI,GAAI,OAAA;AAExC,QAAA,IAAI,EAAA,KAAO,MAAA,IAAU,EAAA,KAAO,SAAA,EAAW;AACrC,UAAA,MAAM,IAAI,mBAAmB,gCAAA,EAAkC;AAAA,YAC7D,QAAA,EAAU,EAAA;AAAA,YACV,MAAA,EAAQ,QAAA;AAAA,YACR,MAAA,EAAQ,IAAA;AAAA,YACR,KAAA,EAAO,EAAA;AAAA,YACP,IAAA,EAAM,KAAK,QAAA,CAAS;AAAA,WACrB,CAAA;AAAA,QACH;AAEA,QAAA,IAAI,cAAc,IAAA,EAAM;AACtB,UAAA,gBAAA,CAAiB,SAAA,EAAW,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA;AAAA,QAChD;AAgBA,QAAA,MAAM,MAAA,GAAS,cAAc,IAAA,GAAO,IAAA,CAAK,UAAW,IAAA,CAAK,QAAA,CAAS,EAAE,CAAA,IAAK,IAAA,CAAK,OAAA;AAE9E,QAAA,OAAO,MAAA,CAAO,YAAY,eAAA,CAAgB,UAAA,CAAW,OAAO,CAAA,EAAG,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AAAA,UAClF,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAMA,MAAA,EAAQ,QAAQ,MAAA,KAAW,MAAA,GAAa,KAAK,QAAA,CAAS,MAAA,IAAU,OAAQ,OAAA,CAAQ,MAAA;AAAA,UAChF,kBAAkB,EAAA,KAAO,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAKzB,GAAI,SAAA,KAAc,IAAA,GAAO,EAAC,GAAI,EAAC,QAAQ,KAAA;AAAK,SAC7C,CAAA;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYA,MAAM,IAAA,CAAK,OAAA,GAAU,EAAC,EAAG;AACvB,QAAA,IAAA,CAAK,kBAAkB,MAAM,CAAA;AAE7B,QAAA,OAAO,MAAM,IAAA,CAAK,WAAA,CAAY,YAAY,MAAM,KAAK,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM,CAAC,QAAQ,MAAA,KAAW,MAAA,CAAO,IAAA,CAAK,MAAM,CAAC,CAAC,CAAA;AAAA,MACpH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,MAAM,OAAA,CAAQ,OAAA,GAAU,EAAC,EAAG;AAC1B,QAAA,IAAA,CAAK,kBAAkB,SAAS,CAAA;AAEhC,QAAA,OAAO,MAAM,IAAA,CAAK,WAAA;AAAA,UAChB,YAAY,MAAM,IAAA,CAAK,KAAA,CAAM,OAAA,EAAS,KAAA,EAAO,CAAC,MAAA,EAAQ,MAAA,KAAW,MAAA,CAAO,YAAA,CAAa,MAAM,CAAC;AAAA,SAC9F;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,MAAM,KAAA,GAAQ;AACZ,QAAA,IAAI,KAAK,OAAA,EAAS;AAChB,UAAA;AAAA,QACF;AAEA,QAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAIf,QAAA,MAAM,IAAA,CAAK,KAAA;AAMX,QAAA,KAAA,MAAW,MAAA,IAAU,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,EAAG;AACjD,UAAA,MAAA,EAAQ,SAAA,EAAU;AAAA,QACpB;AAEA,QAAA,IAAA,CAAK,QAAA,GAAW,EAAC,IAAA,EAAM,IAAA,EAAM,SAAS,IAAA,EAAI;AAC1C,QAAA,IAAA,CAAK,QAAQ,SAAA,EAAU;AACvB,QAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAAA,MACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,OAAO,MAAA,CAAO,YAAY,CAAA,GAAI;AAC5B,QAAA,MAAM,KAAK,KAAA,EAAM;AAAA,MACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,kBAAkB,IAAA,EAAM;AACtB,QAAA,IAAI,KAAK,OAAA,EAAS;AAChB,UAAA,MAAM,IAAI,mBAAmB,mDAAA,EAAqD;AAAA,YAChF,MAAA,EAAQ,QAAA;AAAA,YACR,IAAA;AAAA,YACA,IAAA,EAAM,KAAK,QAAA,CAAS;AAAA,WACrB,CAAA;AAAA,QACH;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,MAAM,YAAY,IAAA,EAAM;AACtB,QAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAM,IAAI,CAAA;AAItC,QAAA,IAAA,CAAK,QAAQ,GAAA,CAAI,IAAA;AAAA,UACf,MAAM,MAAA;AAAA,UACN,MAAM;AAAA,SACR;AAEA,QAAA,OAAO,MAAM,GAAA;AAAA,MACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAsBA,MAAM,KAAA,CAAM,OAAA,EAAS,MAAA,EAAQ,IAAA,EAAM;AACjC,QAAA,MAAM,EAAC,aAAA,EAAAK,cAAAA,EAAa,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,kBAAA,EAAA,EAAA,qBAAA,CAAA,CAAA;AAC9B,QAAA,MAAM,IAAA,GAAO,SAAS,MAAA,GAAS,SAAA;AAE/B,QAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACxB,UAAA,MAAMG,OAAAA,GAAS,IAAIH,cAAAA,CAAc,IAAA,CAAK,SAAS,IAAA,EAAM;AAAA,YACnD,GAAG,iBAAA,CAAkB,IAAA,CAAK,QAAQ,CAAA;AAAA,YAClC,gBAAA,EAAkB;AAAA,WACnB,CAAA;AAED,UAAAG,QAAO,WAAA,EAAY;AACnB,UAAA,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,GAAIA,OAAAA;AAAA,QACxB;AAEA,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA;AAIjC,QAAA,MAAA,CAAO,iBAAA,CAAkB,QAAQ,MAAA,KAAW,MAAA,GAAa,KAAK,QAAA,CAAS,MAAA,IAAU,IAAA,GAAQ,OAAA,CAAQ,MAAM,CAAA;AAKvG,QAAA,MAAA,CAAO,eAAA,CAAgB;AAAA,UACrB,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc,IAAA,CAAK,QAAA,CAAS,UAAA;AAAA,UAChD,MAAA,EAAQ,OAAA,CAAQ,MAAA,IAAU,IAAA,CAAK,QAAA,CAAS;AAAA,SACzC,CAAA;AAED,QAAA,OAAO,MAAM,IAAA,CAAK,MAAA,EAAQ,UAAA,CAAW,OAAO,CAAC,CAAA;AAAA,MAC/C;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACvMA,SAAS,mBAAmB,SAAA,EAAW;AACrC,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,SAAA;AAAA,IACX,SAAA,EAAW,CAAA;AAAA,IACX,QAAA,EAAU,CAAA;AAAA,IACV,IAAA,EAAM,CAAA;AAAA,IACN,WAAA,EAAa,CAAA;AAAA,IACb,MAAA,EAAQ,CAAA;AAAA,IACR,MAAA,EAAQ,CAAA;AAAA,IACR,OAAA,EAAS,EAAA;AAAA,IACT,YAAA,EAAc;AAAA,MACZ,IAAA,EAAM,SAAA;AAAA,MACN,IAAA,EAAM,GAAA;AAAA,MACN,OAAA,EAAS,GAAA;AAAA,MACT,GAAA,EAAK,EAAA;AAAA,MACL,GAAA,EAAK,EAAA;AAAA,MACL,IAAA,EAAM;AAAA,KACR;AAAA,IACA,MAAM;AAAC,GACT;AACF;AASA,SAAS,cAAc,OAAA,EAAS;AAC9B,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,KAAA;AAAA,IACX,UAAA,EAAY,EAAA;AAAA,IACZ,aAAA,EAAe,EAAA;AAAA,IACf,mBAAA,EAAqB,EAAA;AAAA,IACrB,iBAAA,EAAmB,EAAA;AAAA,IACnB,cAAA,EAAgB,EAAA;AAAA,IAChB,YAAA,EAAc,EAAA;AAAA,IACd,SAAA,EAAW,EAAA;AAAA,IACX,MAAA,EAAQ;AAAA,MACN,cAAA,EAAgB,OAAA,CAAQ,GAAA,CAAI,kBAAkB;AAAA,KAChD;AAAA,IACA,WAAA,EAAa,CAAA;AAAA,IACb,cAAA,EAAgB,CAAA;AAAA,IAChB,MAAA,EAAQ,CAAA;AAAA,IACR,MAAA,EAAQ,CAAA;AAAA,IACR,WAAA,EAAa,EAAA;AAAA,IACb,OAAA,EAAS,EAAA;AAAA,IACT,cAAA,EAAgB,EAAA;AAAA,IAChB,SAAA,EAAW,EAAA;AAAA,IACX,aAAA,EAAe,EAAA;AAAA,IACf,SAAS;AAAC,GACZ;AACF;AA3KA,IAgLa;AAhLb,IAAA,iBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,qBAAA,GAAA;AAEA,IAAA,cAAA,EAAA;AACA,IAAA,cAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AACA,IAAA,kBAAA,EAAA;AAiHS,IAAA,MAAA,CAAA,kBAAA,EAAA,oBAAA,CAAA;AA6BA,IAAA,MAAA,CAAA,aAAA,EAAA,eAAA,CAAA;AA6BF,IAAM,YAAA,GAAN,MAAM,aAAA,CAAa;AAAA,MAhL1B;AAgL0B,QAAA,MAAA,CAAA,IAAA,EAAA,cAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBxB,WAAA,CAAY,MAAM,OAAA,EAAS,QAAA,GAAW,MAAM,SAAA,GAAY,IAAA,EAAM,gBAAgB,IAAA,EAAM;AAClF,QAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,QAAA,IAAA,CAAK,QAAA,GAAW,OAAA;AAChB,QAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AAEjB,QAAA,IAAA,CAAK,aAAA,GAAgB,KAAA;AACrB,QAAA,IAAA,CAAK,UAAA,GAAa,SAAA;AAElB,QAAA,IAAA,CAAK,cAAA,GAAiB,mBAAA;AAAA,UACpB,sBAAA;AAAA;AAAA,YAEE,aAAA,KAAkB,aAAa,IAAA,IAAQ,OAAO,aAAa,QAAA,GAAW,QAAA,CAAS,cAAc,CAAA,GAAI,IAAA;AAAA,WACnG;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,IAAA,GAAO;AACT,QAAA,OAAO,IAAA,CAAK,KAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,OAAA,GAAU;AACZ,QAAA,OAAO,IAAA,CAAK,QAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA,MAKA,IAAI,KAAA,GAAQ;AACV,QAAA,OAAO,CAAC,IAAA,CAAK,KAAA,CAAM,MAAA,EAAQ,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA,MACjD;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,IAAI,QAAA,GAAW;AACb,QAAA,OAAO,IAAA,CAAK,SAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAqBA,IAAI,aAAA,GAAgB;AAClB,QAAA,OAAO,IAAA,CAAK,cAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBA,IAAI,SAAA,GAAY;AACd,QAAA,OAAO,IAAA,CAAK,UAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,IAAI,YAAA,GAAe;AACjB,QAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACnB,UAAA,OAAO,EAAC;AAAA,QACV;AAEA,QAAA,MAAM,SAAS,IAAA,CAAK,SAAA;AACpB,QAAA,OAAO;AAAA,UACL,WAAW,MAAA,CAAO,SAAA;AAAA,UAClB,YAAY,MAAA,CAAO,UAAA;AAAA,UACnB,eAAe,MAAA,CAAO,aAAA;AAAA,UACtB,qBAAqB,MAAA,CAAO,mBAAA;AAAA,UAC5B,mBAAmB,MAAA,CAAO,iBAAA;AAAA,UAC1B,gBAAgB,MAAA,CAAO,cAAA;AAAA,UACvB,cAAc,MAAA,CAAO,YAAA;AAAA,UACrB,WAAW,MAAA,CAAO,SAAA;AAAA,UAClB,aAAa,MAAA,CAAO,WAAA;AAAA,UACpB,gBAAgB,MAAA,CAAO,cAAA;AAAA,UACvB,QAAQ,MAAA,CAAO,MAAA;AAAA,UACf,QAAQ,MAAA,CAAO,MAAA;AAAA,UACf,aAAa,MAAA,CAAO,WAAA;AAAA,UACpB,SAAS,MAAA,CAAO,OAAA;AAAA,UAChB,gBAAgB,MAAA,CAAO,cAAA;AAAA,UACvB,WAAW,MAAA,CAAO,SAAA;AAAA,UAClB,eAAe,MAAA,CAAO,aAAA;AAAA,UACtB,SAAS,MAAA,CAAO;AAAA,SAClB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,iBAAiB,SAAA,EAAW;AAC1B,QAAA,IAAI,CAAC,IAAA,CAAK,SAAA,IAAa,CAAC,IAAA,CAAK,SAAA,CAAU,MAAA,IAAU,CAAC,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,cAAA,EAAgB;AACtF,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,IAAI,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,cAAA;AACnC,QAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC1B,UAAA,MAAA,GAAS,CAAC,MAAM,CAAA;AAAA,QAClB;AAEA,QAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,cAAc,SAAS,CAAA;AAC1D,QAAA,IAAI,CAAC,KAAA,EAAO;AACV,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,OAAO;AAAA,UACL,WAAW,KAAA,CAAM,SAAA;AAAA,UACjB,WAAW,KAAA,CAAM,SAAA;AAAA,UACjB,UAAU,KAAA,CAAM,QAAA;AAAA,UAChB,MAAM,KAAA,CAAM,IAAA;AAAA,UACZ,aAAa,KAAA,CAAM,WAAA;AAAA,UACnB,QAAQ,KAAA,CAAM,MAAA;AAAA,UACd,QAAQ,KAAA,CAAM,MAAA;AAAA,UACd,SAAS,KAAA,CAAM,OAAA;AAAA,UACf,cAAc,KAAA,CAAM,YAAA;AAAA,UACpB,MAAM,KAAA,CAAM;AAAA,SACd;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,mBAAA,GAAsB;AACpB,QAAA,IAAI,CAAC,IAAA,CAAK,SAAA,IAAa,CAAC,IAAA,CAAK,SAAA,CAAU,MAAA,IAAU,CAAC,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,cAAA,EAAgB;AACtF,UAAA,OAAO,EAAC;AAAA,QACV;AAEA,QAAA,IAAI,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,cAAA;AACnC,QAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC1B,UAAA,MAAA,GAAS,CAAC,MAAM,CAAA;AAAA,QAClB;AAEA,QAAA,OAAO,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,UAC5B,WAAW,KAAA,CAAM,SAAA;AAAA,UACjB,WAAW,KAAA,CAAM,SAAA;AAAA,UACjB,UAAU,KAAA,CAAM,QAAA;AAAA,UAChB,MAAM,KAAA,CAAM,IAAA;AAAA,UACZ,aAAa,KAAA,CAAM,WAAA;AAAA,UACnB,QAAQ,KAAA,CAAM,MAAA;AAAA,UACd,QAAQ,KAAA,CAAM,MAAA;AAAA,UACd,SAAS,KAAA,CAAM,OAAA;AAAA,UACf,cAAc,KAAA,CAAM,YAAA;AAAA,UACpB,MAAM,KAAA,CAAM;AAAA,SACd,CAAE,CAAA;AAAA,MACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA+BA,YAAA,GAAe;AACb,QAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACnB,UAAA,IAAA,CAAK,SAAA,GAAY,aAAA,CAAc,IAAA,CAAK,QAAQ,CAAA;AAAA,QAC9C,CAAA,MAAA,IAAW,CAAC,IAAA,CAAK,aAAA,EAAe;AAE9B,UAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,cAAc,CAAA;AAC5C,UAAA,IAAA,CAAK,SAAA,GAAY,eAAA,CAAgB,IAAA,CAAK,SAAS,CAAA;AAC/C,UAAA,IAAI,MAAA,EAAQ;AACV,YAAA,mBAAA,CAAoB,IAAA,CAAK,WAAW,MAAM,CAAA;AAAA,UAC5C;AAAA,QACF;AACA,QAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,QAAA,OAAO,IAAA,CAAK,SAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,gBAAgB,QAAA,EAAU;AACxB,QAAA,MAAM,MAAA,GAAS,KAAK,YAAA,EAAa;AAGjC,QAAA,MAAM,gBAAA,GAAmB;AAAA,UACvB,WAAA;AAAA,UACA,YAAA;AAAA,UACA,eAAA;AAAA,UACA,qBAAA;AAAA,UACA,mBAAA;AAAA,UACA,gBAAA;AAAA,UACA,cAAA;AAAA,UACA,WAAA;AAAA,UACA,aAAA;AAAA,UACA,SAAA;AAAA,UACA,gBAAA;AAAA,UACA,WAAA;AAAA,UACA,eAAA;AAAA,UACA;AAAA,SACF;AAGA,QAAA,MAAM,YAAA,GAAe;AAAA,UACnB,SAAA,EAAW,WAAA;AAAA,UACX,UAAA,EAAY,YAAA;AAAA,UACZ,aAAA,EAAe,eAAA;AAAA,UACf,mBAAA,EAAqB,qBAAA;AAAA,UACrB,iBAAA,EAAmB,mBAAA;AAAA,UACnB,cAAA,EAAgB,gBAAA;AAAA,UAChB,YAAA,EAAc,cAAA;AAAA,UACd,SAAA,EAAW,WAAA;AAAA,UACX,WAAA,EAAa,aAAA;AAAA,UACb,OAAA,EAAS,SAAA;AAAA,UACT,cAAA,EAAgB,gBAAA;AAAA,UAChB,SAAA,EAAW,WAAA;AAAA,UACX,aAAA,EAAe,eAAA;AAAA,UACf,OAAA,EAAS;AAAA,SACX;AAEA,QAAA,gBAAA,CAAiB,OAAA,CAAQ,CAAC,KAAA,KAAU;AAElC,UAAA,IAAI,QAAA,CAAS,KAAK,CAAA,KAAM,MAAA,EAAW;AAEjC,YAAA,MAAA,CAAO,YAAA,CAAa,KAAK,CAAC,CAAA,GAAI,SAAS,KAAK,CAAA;AAAA,UAC9C;AAAA,QACF,CAAC,CAAA;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAqBA,gBAAA,CAAiB,WAAW,QAAA,EAAU;AACpC,QAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,QAAA,CAAS,SAAS,CAAA,EAAG;AACtC,UAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,QAAA,EAAW,SAAS,CAAA,gBAAA,CAAA,EAAoB;AAAA,YACnE,MAAA,EAAQ,SAAA;AAAA,YACR,kBAAkB,IAAA,CAAK;AAAA,WACxB,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,MAAA,GAAS,KAAK,YAAA,EAAa;AACjC,QAAA,IAAI,CAAC,MAAA,CAAO,MAAA,IAAU,OAAO,MAAA,CAAO,WAAW,QAAA,IAAY,CAAC,MAAA,CAAO,MAAA,CAAO,cAAA,EAAgB;AACxF,UAAA,MAAA,CAAO,MAAA,GAAS,EAAC,cAAA,EAAgB,EAAC,EAAC;AAAA,QACrC;AAEA,QAAA,IAAI,MAAA,GAAS,OAAO,MAAA,CAAO,cAAA;AAC3B,QAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC1B,UAAA,MAAA,GAAS,CAAC,MAAM,CAAA;AAChB,UAAA,MAAA,CAAO,OAAO,cAAA,GAAiB,MAAA;AAAA,QACjC;AAEA,QAAA,IAAI,QAAQ,MAAA,CAAO,IAAA,CAAK,CAAoB,CAAA,KAAM,CAAA,CAAE,cAAc,SAAS,CAAA;AAC3E,QAAA,IAAI,CAAC,KAAA,EAAO;AACV,UAAA,KAAA,GAAQ,mBAAmB,SAAS,CAAA;AACpC,UAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,QACnB;AAGA,QAAA,IAAI,QAAA,CAAS,YAAY,MAAA,EAAW;AAClC,UAAA,KAAA,CAAM,UAAU,QAAA,CAAS,OAAA;AAAA,QAC3B;AACA,QAAA,IAAI,QAAA,CAAS,iBAAiB,MAAA,EAAW;AACvC,UAAA,KAAA,CAAM,eAAe,QAAA,CAAS,YAAA;AAAA,QAChC;AACA,QAAA,IAAI,QAAA,CAAS,SAAS,MAAA,EAAW;AAC/B,UAAA,KAAA,CAAM,OAAO,QAAA,CAAS,IAAA;AAAA,QACxB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,IAAA,CAAK,IAAI,CAAA,EAAG;AACV,QAAA,IAAI,OAAO,MAAM,QAAA,IAAY,CAAC,OAAO,SAAA,CAAU,CAAC,CAAA,IAAK,CAAA,GAAI,CAAA,EAAG;AAC1D,UAAA,MAAM,IAAI,mBAAmB,wCAAA,EAA0C;AAAA,YACrE,QAAA,EAAU,CAAA;AAAA,YACV,MAAM,OAAO;AAAA,WACd,CAAA;AAAA,QACH;AACA,QAAA,OAAO,IAAI,aAAA,CAAa,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA,EAAG,CAAC,CAAA,EAAG,IAAA,CAAK,QAAA,EAAU,IAAA,CAAK,SAAA,EAAW,IAAA,EAAM,KAAK,cAAc,CAAA;AAAA,MAC1G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,IAAA,CAAK,IAAI,CAAA,EAAG;AACV,QAAA,IAAI,OAAO,MAAM,QAAA,IAAY,CAAC,OAAO,SAAA,CAAU,CAAC,CAAA,IAAK,CAAA,GAAI,CAAA,EAAG;AAC1D,UAAA,MAAM,IAAI,mBAAmB,wCAAA,EAA0C;AAAA,YACrE,QAAA,EAAU,CAAA;AAAA,YACV,MAAM,OAAO;AAAA,WACd,CAAA;AAAA,QACH;AACA,QAAA,OAAO,IAAI,aAAA;AAAA,UACT,CAAA,KAAM,IAAI,EAAC,GAAI,KAAK,KAAA,CAAM,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,UAClC,IAAA,CAAK,QAAA;AAAA,UACL,IAAA,CAAK,SAAA;AAAA,UACL,IAAA;AAAA,UACA,IAAA,CAAK;AAAA,SACP;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,QAAQ,IAAA,EAAM;AACZ,QAAA,KAAA,MAAW,SAAS,IAAA,EAAM;AACxB,UAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA,EAAG;AACzD,YAAA,MAAM,IAAI,mBAAmB,iCAAA,EAAmC;AAAA,cAC9D,QAAA,EAAU,KAAA;AAAA,cACV,MAAM,OAAO;AAAA,aACd,CAAA;AAAA,UACH;AACA,UAAA,IAAI,KAAA,GAAQ,CAAA,IAAK,KAAA,IAAS,IAAA,CAAK,MAAM,MAAA,EAAQ;AAC3C,YAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,UAAA,EAAa,KAAK,CAAA,cAAA,CAAA,EAAkB;AAAA,cAC/D,KAAA;AAAA,cACA,YAAY,CAAC,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,SAAS,CAAC,CAAA;AAAA,cACrC,UAAA,EAAY,KAAK,KAAA,CAAM;AAAA,aACxB,CAAA;AAAA,UACH;AAAA,QACF;AACA,QAAA,OAAO,IAAI,aAAA;AAAA,UACT,KAAK,GAAA,CAAI,CAAC,UAAU,IAAA,CAAK,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,UACrC,IAAA,CAAK,QAAA;AAAA,UACL,IAAA,CAAK,SAAA;AAAA,UACL,IAAA;AAAA,UACA,IAAA,CAAK;AAAA,SACP;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUA,EAAA,CAAG,KAAK,MAAA,EAAQ;AACd,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,CAAW,GAAA,EAAK,MAAM,CAAA;AAEzC,QAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,KAAK,CAAA;AAAA,MAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAoBA,MAAA,CAAO,KAAK,MAAA,EAAQ;AAClB,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,CAAW,GAAA,EAAK,MAAM,CAAA;AACzC,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,EAAE,KAAK,CAAA;AAEnC,QAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,UAAA,OAAO,KAAA;AAAA,QACT;AAEA,QAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,UAAA,MAAM,KAAA,GAAQ,kBAAA,CAAmB,IAAA,CAAK,cAAA,EAAgB,MAAM,CAAA;AAE5D,UAAA,OAAO,KAAA,KAAU,IAAA,GAAO,IAAA,GAAO,YAAA,CAAa,OAAO,KAAK,CAAA;AAAA,QAC1D;AAEA,QAAA,MAAM,IAAA,GAAO,OAAO,KAAK,CAAA;AAEzB,QAAA,OAAO,SAAS,IAAA,IAAQ,OAAO,KAAK,IAAA,KAAS,QAAA,GAAW,KAAK,IAAA,GAAO,IAAA;AAAA,MACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,UAAA,CAAW,KAAK,MAAA,EAAQ;AACtB,QAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,CAAC,MAAA,CAAO,SAAA,CAAU,GAAG,CAAA,EAAG;AACrD,UAAA,MAAM,IAAI,mBAAmB,8BAAA,EAAgC;AAAA,YAC3D,QAAA,EAAU,GAAA;AAAA,YACV,MAAM,OAAO;AAAA,WACd,CAAA;AAAA,QACH;AACA,QAAA,IAAI,GAAA,GAAM,CAAA,IAAK,GAAA,IAAO,IAAA,CAAK,MAAM,MAAA,EAAQ;AACvC,UAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,UAAA,EAAa,GAAG,CAAA,cAAA,CAAA,EAAkB;AAAA,YAC7D,KAAA,EAAO,GAAA;AAAA,YACP,YAAY,CAAC,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,SAAS,CAAC,CAAA;AAAA,YACrC,UAAA,EAAY,KAAK,KAAA,CAAM;AAAA,WACxB,CAAA;AAAA,QACH;AACA,QAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,EAAG;AACnC,UAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,QAAA,EAAW,MAAM,CAAA,gBAAA,CAAA,EAAoB;AAAA,YAChE,MAAA;AAAA,YACA,kBAAkB,IAAA,CAAK;AAAA,WACxB,CAAA;AAAA,QACH;AACA,QAAA,OAAO,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,MAAM,CAAA;AAAA,MACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASA,UAAU,IAAA,EAAM;AACd,QAAA,KAAA,MAAW,UAAU,IAAA,EAAM;AACzB,UAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,QAAA,CAAS,MAAM,CAAA,EAAG;AACnC,YAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,QAAA,EAAW,MAAM,CAAA,gBAAA,CAAA,EAAoB;AAAA,cAChE,MAAA;AAAA,cACA,kBAAkB,IAAA,CAAK;AAAA,aACxB,CAAA;AAAA,UACH;AAAA,QACF;AACA,QAAA,MAAM,OAAA,GAAU,KAAK,GAAA,CAAI,CAAC,QAAQ,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,GAAG,CAAC,CAAA;AAC5D,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,CAAC,GAAA,KAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,KAAA,KAAU,GAAA,CAAI,KAAK,CAAC,CAAC,CAAA;AACvE,QAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,CAAI,CAAC,UAAU,IAAA,CAAK,QAAA,CAAS,KAAK,CAAC,CAAA;AAE3D,QAAA,OAAO,IAAI,cAAa,IAAA,EAAM,OAAA,EAAS,KAAK,SAAA,EAAW,IAAA,EAAM,KAAK,cAAc,CAAA;AAAA,MAClF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYA,MAAM,MAAA,GAAS;AACb,QAAA,OAAO,KAAK,MAAA,EAAO;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,MAAA,GAAS;AACP,QAAA,OAAO;AAAA,UACL,SAAS,IAAA,CAAK,QAAA;AAAA,UACd,MAAM,IAAA,CAAK,KAAA;AAAA,UACX,UAAU,IAAA,CAAK,SAAA;AAAA,UACf,eAAe,IAAA,CAAK;AAAA,SACtB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA6BA,MAAM,KAAA,CAAMT,KAAAA,EAAM,OAAA,GAAU,EAAC,EAAG;AAC9B,QAAA,MAAM,EAAC,aAAA,EAAAU,cAAAA,EAAa,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,kBAAA,EAAA,EAAA,qBAAA,CAAA,CAAA;AAC9B,QAAA,MAAM,aAAA,GAAgB;AAAA,UACpB,YAAY,OAAA,CAAQ,UAAA;AAAA,UACpB,YAAY,OAAA,CAAQ,UAAA;AAAA,UACpB,QAAQ,OAAA,CAAQ,MAAA;AAAA,UAChB,OAAO,OAAA,CAAQ;AAAA,SACjB;AACA,QAAA,MAAM,IAAIA,cAAAA,CAAcV,KAAAA,EAAM,IAAA,EAAM,aAAa,EAAE,IAAA,EAAK;AAAA,MAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAqDA,aAAa,OAAA,CAAQA,KAAAA,EAAM,OAAA,GAAU,EAAC,EAAG;AACvC,QAAA,MAAM,EAAC,aAAA,EAAAM,cAAAA,EAAa,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,kBAAA,EAAA,EAAA,qBAAA,CAAA,CAAA;AAE9B,QAAA,OAAO,MAAM,IAAIA,cAAAA,CAAcN,KAAAA,EAAM,iBAAA,CAAkB,OAAO,CAAC,CAAA,CAAE,IAAA,CAAK,UAAA,CAAW,OAAO,CAAC,CAAA;AAAA,MAC3F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmDA,cAAc,OAAA,CAAQA,KAAAA,EAAM,OAAA,GAAU,EAAC,EAAG;AACxC,QAAA,MAAM,EAAC,aAAA,EAAAM,cAAAA,EAAa,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,kBAAA,EAAA,EAAA,qBAAA,CAAA,CAAA;AAE9B,QAAA,MAAM,SAAS,IAAIA,cAAAA,CAAcN,KAAAA,EAAM,iBAAA,CAAkB,OAAO,CAAC,CAAA;AAEjE,QAAA,OAAO,MAAA,CAAO,WAAA,CAAY,UAAA,CAAW,OAAO,CAAA,EAAG,QAAQ,SAAA,KAAc,MAAA,GAAY,GAAA,GAAS,OAAA,CAAQ,SAAS,CAAA;AAAA,MAC7G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA8BA,aAAa,YAAA,CAAaA,KAAAA,EAAM,OAAA,GAAU,EAAC,EAAG;AAC5C,QAAA,MAAM,EAAC,aAAA,EAAAM,cAAAA,EAAa,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,kBAAA,EAAA,EAAA,qBAAA,CAAA,CAAA;AAE9B,QAAA,OAAO,MAAM,IAAIA,cAAAA,CAAcN,KAAAA,EAAM,oBAAoB,OAAO,CAAC,EAAE,YAAA,EAAa;AAAA,MAClF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA8CA,aAAa,SAAA,CAAUA,KAAAA,EAAM,OAAA,GAAU,EAAC,EAAG;AACzC,QAAA,MAAM,EAAC,aAAA,EAAAM,cAAAA,EAAa,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,kBAAA,EAAA,EAAA,qBAAA,CAAA,CAAA;AAC9B,QAAA,MAAM,EAAC,EAAA,GAAK,MAAA,EAAQ,SAAA,GAAY,MAAI,GAAI,OAAA;AAExC,QAAA,IAAI,EAAA,KAAO,MAAA,IAAU,EAAA,KAAO,SAAA,EAAW;AACrC,UAAA,MAAM,IAAI,mBAAmB,gCAAA,EAAkC;AAAA,YAC7D,QAAA,EAAU,EAAA;AAAA,YACV,MAAA,EAAQ,QAAA;AAAA,YACR,MAAA,EAAQ,IAAA;AAAA,YACR,KAAA,EAAO,EAAA;AAAA,YACP,IAAA,EAAMN;AAAA,WACP,CAAA;AAAA,QACH;AAEA,QAAA,IAAI,cAAc,IAAA,EAAM;AACtB,UAAA,gBAAA,CAAiB,WAAWA,KAAI,CAAA;AAAA,QAClC;AAEA,QAAA,MAAM,MAAA,GAAS,IAAIM,cAAAA,CAAcN,KAAAA,EAAM,EAAC,GAAG,iBAAA,CAAkB,OAAO,CAAA,EAAG,gBAAA,EAAkB,EAAA,KAAO,MAAA,EAAO,CAAA;AAEvG,QAAA,OAAO,MAAM,OAAO,SAAA,CAAU,UAAA,CAAW,OAAO,CAAA,EAAG,EAAC,WAAU,CAAA;AAAA,MAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAqCA,aAAa,IAAA,CAAKA,KAAAA,EAAM,OAAA,GAAU,EAAC,EAAG;AACpC,QAAA,MAAM,EAAC,aAAA,EAAAM,cAAAA,EAAa,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,kBAAA,EAAA,EAAA,qBAAA,CAAA,CAAA;AAC9B,QAAA,MAAM,EAAC,OAAA,EAAAK,QAAAA,EAAO,GAAI,MAAM,OAAA,CAAA,OAAA,EAAA,CAAA,IAAA,CAAA,OAAA,YAAA,EAAA,EAAA,eAAA,CAAA,CAAA;AAIxB,QAAA,MAAM,SAAS,IAAIL,cAAAA,CAAcN,KAAAA,EAAM,iBAAA,CAAkB,OAAO,CAAC,CAAA;AAMjE,QAAA,MAAA,CAAO,WAAA,EAAY;AAKnB,QAAA,MAAM,OAAO,eAAA,EAAgB;AAE7B,QAAA,OAAO,IAAIW,QAAAA,CAAQ,MAAA,EAAQ,MAAA,CAAO,cAAA,EAAe,EAAG,EAAC,GAAG,OAAA,EAAS,IAAA,EAAAX,KAAAA,EAAK,CAAA;AAAA,MACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeA,aAAa,SAAS,IAAA,EAAM;AAC1B,QAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACjB,UAAA,MAAM,IAAI,mBAAmB,+EAAA,EAAiF;AAAA,YAC5G;AAAA,WACD,CAAA;AAAA,QACH;AACA,QAAA,IAAI,CAAC,KAAK,IAAA,EAAM;AACd,UAAA,MAAM,IAAI,mBAAmB,4EAAA,EAA8E;AAAA,YACzG;AAAA,WACD,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,EAAC,QAAA,GAAW,IAAA,EAAM,aAAA,GAAgB,MAAI,GAAI,IAAA;AAEhD,QAAA,IAAI,QAAA,KAAa,IAAA,IAAQ,CAAC,aAAA,CAAc,QAAQ,CAAA,EAAG;AACjD,UAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,qCAAA,EAAwC,YAAA,CAAa,QAAQ,CAAC,CAAA,CAAA,EAAI;AAAA,YAC7F,MAAM,OAAO;AAAA,WACd,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,MAAA,GAAS,uBAAuB,aAAa,CAAA;AAEnD,QAAA,IAAI,WAAW,IAAA,EAAM;AACnB,UAAA,MAAM,OAAA,GAAU,MAAA,CAAO,IAAA,CAAK,CAAC,KAAA,KAAU,CAAC,IAAA,CAAK,OAAA,CAAQ,QAAA,CAAS,KAAA,CAAM,KAAK,CAAC,CAAA;AAE1E,UAAA,IAAI,YAAY,MAAA,EAAW;AACzB,YAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,2BAAA,EAA8B,OAAA,CAAQ,KAAK,CAAA,kCAAA,CAAA,EAAsC;AAAA,cAC5G,OAAO,OAAA,CAAQ,KAAA;AAAA,cACf,kBAAkB,IAAA,CAAK;AAAA,aACxB,CAAA;AAAA,UACH;AAAA,QACF;AAEA,QAAA,OAAO,IAAI,cAAa,IAAA,CAAK,IAAA,EAAM,KAAK,OAAA,EAAS,QAAA,EAAU,MAAM,MAAM,CAAA;AAAA,MACzE;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACvkCA,cAAA,EAAA;AACA,cAAA,EAAA;AACA,gBAAA,EAAA;AASA,SAAS,YAAA,CAAa,OAAO,OAAA,EAAS;AACpC,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,aAAA,CAAc,KAAK,CAAA,EAAG;AACrD,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,IAAI,kBAAA;AAAA,IACR,CAAA,gDAAA,EAAmD,SAAS,CAAA,IAAA,EAAO,SAAS,CAAA,MAAA,CAAA,IACzE,OAAO,KAAA,KAAU,QAAA,GAAW,MAAA,CAAO,KAAK,CAAA,GAAI,YAAA,CAAa,KAAK,CAAA,CAAA;AAAA,IACjE,EAAC,GAAG,OAAA,EAAS,MAAM,SAAA,EAAW,IAAA,EAAM,OAAO,KAAA;AAAK,GAClD;AACF;AAVS,MAAA,CAAA,YAAA,EAAA,cAAA,CAAA;AAwBF,IAAM,SAAA,GAAN,MAAM,UAAA,CAAU;AAAA,EArCvB;AAqCuB,IAAA,MAAA,CAAA,IAAA,EAAA,WAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrB,WAAA,CAAY,QAAA,EAAU,WAAA,EAAa,WAAA,EAAa;AAC9C,IAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AAEjB,IAAA,IAAA,CAAK,YAAA,GAAe,WAAA;AAEpB,IAAA,IAAA,CAAK,YAAA,GAAe,WAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,QAAA,GAAW;AACb,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,WAAA,GAAc;AAChB,IAAA,OAAO,IAAA,CAAK,YAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,WAAA,GAAc;AAChB,IAAA,OAAO,IAAA,CAAK,YAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAA,GAAiB;AACf,IAAA,IAAI,IAAA,IAAQ,KAAK,YAAA,EAAc;AAC7B,MAAA,OAAO,IAAA,CAAK,YAAA;AAAA,IACd,CAAA,MAAA,IAAW,IAAA,IAAQ,IAAA,CAAK,SAAA,EAAW;AACjC,MAAA,OAAO,IAAA,CAAK,SAAA;AAAA,IACd,CAAA,MAAA,IAAW,IAAA,IAAQ,IAAA,CAAK,YAAA,EAAc;AACpC,MAAA,OAAO,IAAA,CAAK,YAAA;AAAA,IACd,CAAA,MAAO;AACL,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,oBAAA,GAAuB;AACrB,IAAA,MAAM,QAAA,GAAW,KAAK,SAAA,IAAa,IAAA;AACnC,IAAA,MAAM,WAAA,GAAc,KAAK,YAAA,IAAgB,IAAA;AACzC,IAAA,MAAM,WAAA,GAAc,KAAK,YAAA,IAAgB,IAAA;AAEzC,IAAA,IAAI,QAAA,KAAa,IAAA,IAAQ,WAAA,KAAgB,IAAA,EAAM;AAC7C,MAAA,MAAM,IAAI,mBAAmB,iDAAA,EAAmD;AAAA,QAC9E,QAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,QAAA,KAAa,IAAA,IAAQ,WAAA,KAAgB,IAAA,IAAQ,gBAAgB,IAAA,EAAM;AACrE,MAAA,MAAM,IAAI,mBAAmB,wCAAA,EAA0C;AAAA,QACrE,QAAA;AAAA,QACA,WAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,aAAa,IAAA,EAAM;AACrB,MAAA,YAAA,CAAa,QAAA,EAAU,EAAE,CAAA;AAAA,IAC3B;AAEA,IAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,MAAA,WAAA,CAAY,WAAA,EAAa,wBAAA,EAA0B,EAAC,IAAA,EAAM,UAAS,CAAA;AAAA,IACrE;AAEA,IAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,MAAA,SAAA,CAAU,WAAA,EAAa,sBAAA,EAAwB,EAAC,IAAA,EAAM,QAAO,CAAA;AAAA,IAC/D;AAEA,IAAA,MAAM,SAAS,QAAA,IAAY,WAAA;AAC3B,IAAA,MAAM,IAAA,GAAO,MAAA,KAAW,IAAA,GAAO,CAAA,GAAA,CAAK,QAAA,KAAa,OAAO,CAAA,GAAI,CAAA,KAAM,WAAA,KAAgB,IAAA,GAAO,CAAA,GAAI,CAAA,CAAA;AAC7F,IAAA,MAAM,SAAS,MAAA,CAAO,WAAA,CAAY,iBAAiB,IAAA,EAAM,MAAA,EAAQ,WAAW,CAAC,CAAA;AAE7E,IAAA,WAAA,CAAY,MAAA,EAAQ,CAAA,EAAG,IAAA,EAAM,MAAA,EAAQ,WAAW,CAAA;AAEhD,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,OAAO,KAAA,EAAO;AACZ,IAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,EAAU;AAC/C,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,MAAM,QAAA,GAAW,KAAK,SAAA,IAAa,IAAA;AACnC,IAAA,MAAM,WAAA,GAAc,KAAK,YAAA,IAAgB,IAAA;AACzC,IAAA,MAAM,WAAA,GAAc,KAAK,YAAA,IAAgB,IAAA;AACzC,IAAA,MAAM,IAAA,GAAO,OAAO,KAAK,CAAA;AAEzB,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,OACE,WAAA,KAAgB,IAAA,IAChB,WAAA,KAAgB,IAAA,CAAK,IAAA,IACpB,QAAA,KAAa,IAAA,MAAW,WAAA,KAAgB,IAAA,CAAA,IAAA,CACxC,QAAA,IAAY,WAAA,MAAiB,IAAA,CAAK,MAAA;AAAA,IAEvC;AAEA,IAAA,IAAI,EAAE,UAAA,IAAc,KAAA,IAAS,aAAA,IAAiB,KAAA,IAAS,iBAAiB,KAAA,CAAA,EAAQ;AAC9E,MAAA,OAAO,KAAA;AAAA,IACT;AAEA,IAAA,OACE,QAAA,MAAc,KAAA,CAAM,QAAA,IAAY,IAAA,CAAA,IAChC,WAAA,MAAiB,MAAM,WAAA,IAAe,IAAA,CAAA,IACtC,WAAA,MAAiB,KAAA,CAAM,WAAA,IAAe,IAAA,CAAA;AAAA,EAE1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,aAAa,QAAA,EAAU;AAC5B,IAAA,YAAA,CAAa,QAAA,EAAU,EAAE,CAAA;AAEzB,IAAA,OAAO,IAAI,UAAA,CAAU,QAAA,EAAU,IAAA,EAAM,IAAI,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,gBAAgB,WAAA,EAAa;AAClC,IAAA,WAAA,CAAY,WAAA,EAAa,wBAAA,EAA0B,EAAC,IAAA,EAAM,UAAS,CAAA;AAEnE,IAAA,OAAO,IAAI,UAAA,CAAU,IAAA,EAAM,WAAA,EAAa,IAAI,CAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,gBAAgB,WAAA,EAAa;AAClC,IAAA,SAAA,CAAU,WAAA,EAAa,sBAAA,EAAwB,EAAC,IAAA,EAAM,QAAO,CAAA;AAE7D,IAAA,OAAO,IAAI,UAAA,CAAU,IAAA,EAAM,IAAA,EAAM,WAAW,CAAA;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,gBAAA,CAAiB,QAAA,EAAU,WAAA,EAAa;AAC7C,IAAA,YAAA,CAAa,QAAA,EAAU,EAAE,CAAA;AACzB,IAAA,SAAA,CAAU,WAAA,EAAa,sBAAA,EAAwB,EAAC,IAAA,EAAM,QAAO,CAAA;AAE7D,IAAA,OAAO,IAAI,UAAA,CAAU,QAAA,EAAU,IAAA,EAAM,WAAW,CAAA;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,mBAAA,CAAoB,WAAA,EAAa,WAAA,EAAa;AACnD,IAAA,WAAA,CAAY,WAAA,EAAa,wBAAA,EAA0B,EAAC,IAAA,EAAM,UAAS,CAAA;AACnE,IAAA,SAAA,CAAU,WAAA,EAAa,sBAAA,EAAwB,EAAC,IAAA,EAAM,QAAO,CAAA;AAE7D,IAAA,OAAO,IAAI,UAAA,CAAU,IAAA,EAAM,WAAA,EAAa,WAAW,CAAA;AAAA,EACrD;AACF;;;AC1QA,YAAA,EAAA;;;ACAA,cAAA,EAAA;AACA,cAAA,EAAA;AAGA,IAAM,aAAA,GAAgB,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,IAAI,EAAE,CAAA;AAE3C,IAAM,UAAA,GAAa,KAAA;AAGnB,IAAM,WAAA,GAAc,MAAA;AAGpB,IAAM,UAAA,GAAA,CAAc,CAAC,WAAA,GAAc,aAAA,IAAiB,UAAA;AACpD,IAAM,UAAA,GAAA,CAAc,cAAc,aAAA,IAAiB,UAAA;AA4B5C,SAAS,iBAAiB,MAAA,EAAQ;AACvC,EAAA,MAAM,IAAA,GAAO,OAAO,MAAM,CAAA;AAC1B,EAAA,MAAM,MAAA,GAAS,IAAA,KAAS,IAAA,GAAO,MAAA,GAAS,IAAA,CAAK,MAAA;AAE7C,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,CAAC,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,EAAG;AAC1D,IAAA,MAAM,IAAI,mBAAmB,4CAAA,EAA8C;AAAA,MACzE,QAAA,EAAU,aAAa,MAAM,CAAA;AAAA,MAC7B,MAAM,OAAO;AAAA,KACd,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,aAAA,GAAgB,SAAS,UAAU,CAAA;AAGzD,EAAA,IAAI,EAAE,IAAA,CAAK,GAAA,CAAI,EAAE,KAAK,WAAA,CAAA,EAAc;AAClC,IAAA,MAAM,IAAI,kBAAA,CAAmB,CAAA,sBAAA,EAAyB,MAAM,CAAA,gDAAA,CAAA,EAAoD;AAAA,MAC9G,MAAA,EAAQ,MAAA;AAAA,MACR,SAAA,EAAW,UAAA;AAAA,MACX,SAAA,EAAW;AAAA,KACZ,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,IAAI,KAAK,EAAE,CAAA;AACpB;AAvBgB,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;AAiDT,SAAS,iBAAiB,IAAA,EAAM;AACrC,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,GAAI,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA,GAAI,MAAA,CAAO,GAAA;AAE3E,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,mBAAmB,qCAAA,EAAuC;AAAA,MAClE,QAAA,EAAU,aAAa,IAAI,CAAA;AAAA,MAC3B,MAAM,OAAO;AAAA,KACd,CAAA;AAAA,EACH;AAEA,EAAA,OAAA,CAAQ,KAAK,aAAA,IAAiB,UAAA;AAChC;AAXgB,MAAA,CAAA,gBAAA,EAAA,kBAAA,CAAA;;;ADxFhB,iBAAA,EAAA;AACA,mBAAA,EAAA;AACA,YAAA,EAAA;AACA,kBAAA,EAAA;AACA,kBAAA,EAAA;AACA,cAAA,EAAA","file":"index.js","sourcesContent":["// @ts-check\n\n/**\n * The name each of this module's classes reports, written out rather than read from the class.\n *\n * A class's own `name` is whatever the build left it: the CommonJS bundle of every release checked from\n * 0.6.2 to 0.11.0 gave these classes no name at all, so `error.name` was `''` for a `require`d qvdjs,\n * and a bundler minifying the source renames them. `error.name` is what callers match on, so it must\n * not depend on either.\n *\n * @type {Map<Function, string>}\n */\nconst ERROR_NAMES = new Map();\n\n/**\n * Base error class for all QVD-related errors.\n * Provides structured error information with error codes and context.\n */\nexport class QvdError extends Error {\n /**\n * Constructs a new QVD error.\n *\n * @param {string} message The error message.\n * @param {string} code The error code.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`, so a `cause` becomes `error.cause`: the\n * error this one reports, such as the operating system's refusal behind a `QvdIOError`.\n */\n constructor(message, code, context = {}, options = undefined) {\n super(message, options);\n // A caller's own subclass keeps its own name.\n this.name = ERROR_NAMES.get(new.target) ?? new.target.name;\n this.code = code;\n this.context = context;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when parsing a QVD file fails.\n * Used for issues during XML header parsing, symbol table parsing, or index table parsing.\n */\nexport class QvdParseError extends QvdError {\n /**\n * Constructs a new QVD parse error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_PARSE_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when input validation fails.\n * Used for invalid parameters, out of bounds access, or missing required data.\n */\nexport class QvdValidationError extends QvdError {\n /**\n * Constructs a new QVD validation error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_VALIDATION_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when the operating system refuses a file-system call made to read or write a QVD\n * file: a missing file, a directory where a file was expected, a permission error, and on Windows a\n * file another process has locked (`EBUSY`). Locks on Linux and macOS are advisory, so a locked file\n * there reads and writes without an error at all.\n *\n * `context.code` is the system code Node reported - `ENOENT`, `EISDIR`, `EACCES`, `EBUSY` and so\n * on - and `context.operation` the call that failed, as Node names it: `open`, `fstat`, `read`,\n * `write`, `ftruncate`, `fsync` and `close`, and from a write that replaces the file rather than\n * rewriting it, `fchmod` and `rename` as well. `context.file` is the resolved path the caller asked\n * for, even where the call that failed was made on the temporary file a write builds beside it;\n * `cause` is Node's own error, unchanged, so its `errno`, `syscall` and the path it names are there\n * too. On Windows a `rename` that reports `EPERM` or `EBUSY` usually means another program has the\n * destination open - Qlik Sense reading it, most often - and the previous file is untouched.\n *\n * `context.temporaryFile` appears on one of these and only one: a write that failed and could not\n * remove the file it was building either, which is the only way one is left behind while a process is\n * still running. It names that file, so a caller can remove it.\n *\n * One has neither `context.code` nor `cause`, though its `code` is `QVD_IO_ERROR` like every other's:\n * a write that stored nothing while the operating system reported no error. There is no system code\n * to carry, so `context.filePosition` says where the file stops.\n */\nexport class QvdIOError extends QvdError {\n /**\n * Constructs a new QVD IO error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_IO_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when a QVD file is corrupted or malformed.\n * Used for missing headers, invalid data structures, or corrupted data.\n */\nexport class QvdCorruptedError extends QvdError {\n /**\n * Constructs a new QVD corrupted error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_CORRUPTED_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when security violations occur.\n * Used for path traversal attempts, XXE attacks, or other security issues.\n *\n * A refused path says why in `context.reason`. `'outside_allowed_directory'` is a path that resolves\n * outside allowedDir, and `'null_byte'` one with a NUL in it. `'changed_after_check'` is a file that\n * was not the one the containment check approved by the time it was opened: `context.change` is\n * `'became_a_symlink'`; `'replaced'` for a different file at the same name; or `'appeared'` for a\n * read that found a file at a name the check found empty. Each, left alone, would have read or\n * written a file the check never saw, and on a sandbox shared with someone else it is what a symlink\n * race looks like. See `openChecked` for what it covers and what it cannot.\n */\nexport class QvdSecurityError extends QvdError {\n /**\n * Constructs a new QVD security error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_SECURITY_ERROR', context, options);\n }\n}\n\nERROR_NAMES.set(QvdError, 'QvdError');\nERROR_NAMES.set(QvdParseError, 'QvdParseError');\nERROR_NAMES.set(QvdValidationError, 'QvdValidationError');\nERROR_NAMES.set(QvdIOError, 'QvdIOError');\nERROR_NAMES.set(QvdCorruptedError, 'QvdCorruptedError');\nERROR_NAMES.set(QvdSecurityError, 'QvdSecurityError');\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * What a QVD symbol can hold, said once.\n *\n * Only the writer used to apply these rules. It defined the int32 range, to choose between an int\n * and a double, and refused NaN, the infinities and a string containing NUL. `QvdSymbol` checked\n * nothing: the RangeError from Node's `writeInt32LE` was its only range check, and it wrote a NUL\n * whole - so the same value could be refused by one and written by the other. Everything that\n * decides whether a number or a text can be stored now reads it from here, and throws from here.\n */\n\n/** Lower bound of the integer a type 1 or type 5 symbol holds. */\nexport const INT32_MIN = -2147483648;\n\n/** Upper bound of the integer a type 1 or type 5 symbol holds. */\nexport const INT32_MAX = 2147483647;\n\n/** Terminates a text in the symbol table, so a stored text cannot contain one. */\nexport const NUL = String.fromCharCode(0);\n\n/**\n * Marks a `QvdDual`, from whichever copy of this library built it.\n *\n * `Symbol.for` rather than `Symbol()`, and a brand rather than `instanceof`, because a cell can come\n * from a different copy of the class than the one checking it: the CommonJS and ESM builds loaded in\n * one process, two installed copies of the package, a Jest module registry that has been reset, or a\n * vm realm. Each has its own `QvdDual`, and `instanceof` answers false across all of them.\n */\nexport const DUAL_BRAND = Symbol.for('qvdjs.QvdDual');\n\n/**\n * The dual value a cell holds, or null when it is not one.\n *\n * A dual is either a `QvdDual` - recognised by its brand, so one built by another copy of this\n * library counts - or a plain object whose own enumerable keys are exactly `number` and `text`. The\n * second form is what every clone of a `QvdDual` produces: `structuredClone`, `postMessage`,\n * `v8.serialize` and `JSON` all keep own enumerable data properties and drop the class, so a frame\n * sent to a worker and back writes the same duals it was read with.\n *\n * The shape is exact because a looser one writes the wrong file silently. An object that merely\n * *has* `number` and `text` - a record `{number, text, date}`, an array given the two properties, an\n * object that inherits them - is somebody's own data, and storing it as a dual would discard the rest\n * of it without a word. It is refused instead, and so is anything that is not a plain object - see\n * `isPlainObject` - so an object literal from a vm realm is accepted where `instanceof Object` would\n * refuse it.\n *\n * The halves are not type-checked here. The caller validates them, so that a refusal can say which\n * half is wrong rather than that the object is not a dual.\n *\n * @param {any} value Any value.\n * @return {{number: any, text: any}|null} The value itself when it is a dual, or null.\n */\nexport function asDual(value) {\n if (value === null || typeof value !== 'object') {\n return null;\n }\n\n try {\n if (value[DUAL_BRAND] === true) {\n return value;\n }\n\n if (!isPlainObject(value)) {\n return null;\n }\n\n const keys = Object.keys(value);\n\n return keys.length === 2 &&\n ((keys[0] === 'number' && keys[1] === 'text') || (keys[0] === 'text' && keys[1] === 'number'))\n ? value\n : null;\n } catch {\n // A revoked Proxy throws from every one of those operations. It is not a dual, and the refusal\n // that follows describes it without touching it again.\n return null;\n }\n}\n\n/**\n * Whether a value is a plain object: an object literal from any realm, or one with a null prototype.\n *\n * Tested as \"a prototype that is null, or whose own prototype is null\", which is what a realm's\n * `Object.prototype` is. An array, a class instance and an object made with `Object.create(other)` are\n * not plain, although an instance of an anonymous class and the last read their constructor name as\n * `Object` through the chain.\n *\n * @param {any} value The value.\n * @return {boolean} True for a plain object.\n * @throws {TypeError} For a revoked Proxy, from `Array.isArray` and `Object.getPrototypeOf`.\n */\nexport function isPlainObject(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || Object.getPrototypeOf(prototype) === null;\n}\n\n/**\n * Whether a text reads as a finite number.\n *\n * This is the rule `{coerceNumericStrings: true}` applies, and the one every read applied from #212 until\n * coercion became opt-in. The reader started from `!isNaN(Number(text))` and was narrowed twice.\n * `Number('')` and `Number(' ')` are 0, which turned every blank cell Qlik stored into a real zero, so\n * blank text is never numeric. And `Number.isFinite` rather than `!isNaN`, because JavaScript reads `E` as\n * an exponent: `Number('8E5597')` is Infinity, and that string is a LEGO colour code in this repository's\n * own `lego/colors.qvd`. A text whose numeric reading is not finite stays text.\n *\n * @param {string} text The text.\n * @return {boolean} True when the text reads as a finite number.\n */\nexport function isNumericText(text) {\n return text.trim() !== '' && Number.isFinite(Number(text));\n}\n\n/**\n * Whether a number is stored as a 32-bit integer rather than as a double.\n *\n * This is the rule Qlik follows, read off the files it wrote rather than chosen here: every numeric\n * symbol in the bundled Qlik files is an int exactly when its value is an integer inside the int32\n * range, whether it is a pure number or a dual. The kind follows the value, never the text.\n *\n * -0 is stored as the integer 0, because `Number.isInteger(-0)` is true and -0 is inside the range.\n * That is the cause, and not a Map folding the two together: a Map only merges 0 and -0 when both\n * occur in one column, and a column holding -0 alone is stored as 0 all the same. Qlik's engine\n * compares -0 equal to 0 and `Num()` shows it as 0.\n *\n * @param {number} value A finite number.\n * @return {boolean} True when the value is stored as an int symbol.\n */\nexport function isStoredAsInt(value) {\n return Number.isInteger(value) && value >= INT32_MIN && value <= INT32_MAX;\n}\n\n/**\n * Why a value cannot be stored as a number, or null when it can.\n *\n * @param {any} value The value.\n * @return {string|null} `'is a string, not a number'` and the like, `'is NaN'`, `'is Infinity'`,\n * `'is -Infinity'`, or null.\n */\nexport function numberProblem(value) {\n if (typeof value !== 'number') {\n return `is ${describeType(value)}, not a number`;\n }\n\n return Number.isFinite(value) ? null : `is ${String(value)}`;\n}\n\n/**\n * Why a value cannot be stored as a text, or null when it can.\n *\n * NUL is refused because it is what ends a text in the symbol table: a text containing one was\n * written whole, and the reader then took the character after it for the next symbol's type byte.\n *\n * An unpaired surrogate is refused because UTF-8 has no encoding for one. A JavaScript string is a\n * sequence of UTF-16 code units, and a code unit from U+D800 to U+DFFF is half of a character unless\n * a high one is followed by a low one. Node writes each half on its own as U+FFFD, the replacement\n * character, so `'\\uD800'` and `'\\uDFFF'` were written as the same three bytes: two different strings\n * became two symbols with one stored value, and neither read back as what was written.\n *\n * A string with both problems reports the NUL.\n *\n * @param {any} value The value.\n * @return {{reason: 'type'|'nul'|'surrogate', position?: number}|null} The problem, with the index of\n * the offending code unit where there is one, or null.\n */\nexport function textProblem(value) {\n if (typeof value !== 'string') {\n return {reason: 'type'};\n }\n\n // indexOf rather than includes: this runs once per distinct value on a table that may have\n // millions of them, and indexOf on a string primitive is the cheaper of the two.\n const position = value.indexOf(NUL);\n\n if (position !== -1) {\n return {reason: 'nul', position};\n }\n\n // isWellFormed is one native call for the whole string, so the scan for where the problem is runs\n // only for a string that is about to be refused.\n return value.isWellFormed() ? null : {reason: 'surrogate', position: unpairedSurrogateIndex(value)};\n}\n\n/**\n * The index of the first code unit in a string that is half of a surrogate pair without the other\n * half.\n *\n * @param {string} value A string that is not well formed.\n * @return {number} The index, or -1 when every surrogate is paired.\n */\nfunction unpairedSurrogateIndex(value) {\n for (let index = 0; index < value.length; index++) {\n const unit = value.charCodeAt(index);\n\n if (unit < 0xd800 || unit > 0xdfff) {\n continue;\n }\n\n // A high surrogate followed by a low one is one character: step over both. charCodeAt past the\n // end is NaN, which fails the comparison, so a high surrogate at the end is unpaired.\n const next = value.charCodeAt(index + 1);\n\n if (unit <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) {\n index++;\n continue;\n }\n\n return index;\n }\n\n return -1;\n}\n\n/**\n * Throws unless a value can be stored as a number.\n *\n * `subject` names the half being checked, as the message starts: `'The double of a symbol'` gives\n * \"The double of a symbol must be a finite number; got a string\". A cell is the exception, and is\n * checked with a null subject: it is already known to be a number, so all that can be wrong with it\n * is NaN or an infinity, and the message for that has been quoted to callers since the writer first\n * refused it.\n *\n * @param {any} value The value.\n * @param {string|null} subject What the value is, capitalised; null for a cell.\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If the value is not a finite number.\n */\nexport function checkNumber(value, subject, context) {\n if (numberProblem(value) === null) {\n return;\n }\n\n if (subject === null && typeof value === 'number') {\n throw new QvdValidationError('NaN and Infinity cannot be stored in a QVD field', {\n ...context,\n provided: String(value),\n });\n }\n\n throw new QvdValidationError(`${subject ?? 'A number'} must be a finite number; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n}\n\n/**\n * Throws unless a value can be stored as a text.\n *\n * @param {any} value The value.\n * @param {string} subject What the value is, capitalised, as the message starts: `'A string value'`\n * gives \"A string value cannot contain a NUL character\".\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If the value is not a string, or holds a NUL or an unpaired surrogate,\n * which no stored text can; `context.position` is that code unit's index.\n */\nexport function checkText(value, subject, context) {\n const problem = textProblem(value);\n\n if (problem === null) {\n return;\n }\n\n if (problem.reason === 'type') {\n throw new QvdValidationError(`${subject} must be a string; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n }\n\n if (problem.reason === 'surrogate') {\n throw new QvdValidationError(`${subject} cannot contain an unpaired surrogate`, {\n ...context,\n position: problem.position,\n });\n }\n\n throw new QvdValidationError(`${subject} cannot contain a NUL character`, {...context, position: problem.position});\n}\n\n/**\n * The name of a value's constructor, read without letting the read throw.\n *\n * A getter, or a revoked Proxy, can throw from `value.constructor`, and an error message is the\n * wrong place to find that out: the caller would get that error instead of the one being built.\n *\n * @param {any} value An object.\n * @return {string|null} The name, or null when there is none to read.\n */\nexport function constructorName(value) {\n try {\n const name = value.constructor?.name;\n\n return typeof name === 'string' && name !== '' ? name : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Names a value's type the way a caller reading an error would.\n *\n * `typeof` alone says \"object\" for a Date, an array and a Map alike, which is the least useful thing\n * it could say in a message whose job is to tell somebody what to convert. The value is never\n * converted to a string along the way: an object's own conversion can throw, or say nothing about\n * what the object is.\n *\n * @param {any} value The value.\n * @return {string} `'a Date'`, `'an array'`, `'a plain object with keys a, b'`, `'a boolean'`,\n * `'NaN'`, and so on.\n */\nexport function describeType(value) {\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'number') {\n // A number that fails a number check is NaN or an infinity, and \"got a number\" would say nothing.\n return Number.isFinite(value) ? 'a number' : String(value);\n }\n\n if (typeof value === 'undefined') {\n return 'undefined';\n }\n\n if (typeof value !== 'object') {\n return `a ${typeof value}`;\n }\n\n let name;\n\n try {\n if (Array.isArray(value)) {\n return 'an array';\n }\n\n // '[object Date]' when there is no constructor name to read: a null prototype, a replaced\n // constructor property.\n name = constructorName(value) ?? Object.prototype.toString.call(value).slice(8, -1);\n\n if (name === 'Object') {\n // The name an object inheriting from another reads through its chain, too - from\n // `Object.create({number: 1, text: 'x'})`, or an instance of an anonymous class - and calling that\n // plain would contradict a message asking for one: \"metadata must be a plain object; got a plain\n // object\".\n if (!isPlainObject(value)) {\n return 'an object whose prototype is not Object.prototype';\n }\n\n const keys = Object.keys(value);\n\n if (keys.length === 0) {\n return 'a plain object';\n }\n\n // Capped, because the message is for a person and an object can have any number of keys.\n return `a plain object with keys ${keys.slice(0, 5).join(', ')}${keys.length > 5 ? ', ...' : ''}`;\n }\n } catch {\n // A revoked Proxy throws from Array.isArray itself.\n return 'an object';\n }\n\n // 'an Error', 'an Int32Array', but 'a Uint8Array': a leading U is read \"you\".\n return `${/^[aeio]/i.test(name) ? 'an' : 'a'} ${name}`;\n}\n","// @ts-check\n\nimport {isStoredAsInt} from './cellRules.js';\n\n/**\n * How one symbol is laid out in the symbol table, said once.\n *\n * | Kind | Bytes after the type byte |\n * | --- | --- |\n * | 1, int | int32, little-endian |\n * | 2, double | float64, little-endian |\n * | 4, string | UTF-8 text, then a NUL |\n * | 5, dual int | int32, then UTF-8 text and a NUL |\n * | 6, dual double | float64, then UTF-8 text and a NUL |\n *\n * Nothing here validates. A caller checks its values through `cellRules` first, and these\n * functions encode what they are given.\n */\n\n/**\n * The kind a value is stored as.\n *\n * The number decides between int and double - through `isStoredAsInt`, which is Qlik's rule - and\n * the presence of a text decides between pure and dual. Nothing else does: a text is never parsed\n * to choose a kind.\n *\n * @param {number|null} number The numeric half, or null for a string.\n * @param {string|null} text The text, or null for a pure number.\n * @return {1|2|4|5|6} The type byte.\n */\nexport function kindOf(number, text) {\n if (number === null) {\n return 4;\n }\n\n if (isStoredAsInt(number)) {\n return text === null ? 1 : 5;\n }\n\n return text === null ? 2 : 6;\n}\n\n/**\n * The bytes one symbol takes, type byte and terminator included.\n *\n * @param {number} kind The type byte.\n * @param {number|null} number The numeric half, unused for kind 4.\n * @param {string|null} text The text, unused for kinds 1 and 2.\n * @return {number} The length in bytes.\n */\nexport function symbolByteLength(kind, number, text) {\n const numberBytes = kind === 1 || kind === 5 ? 4 : kind === 2 || kind === 6 ? 8 : 0;\n // @ts-ignore - a kind of 4, 5 or 6 carries a text\n const textBytes = kind >= 4 ? Buffer.byteLength(text, 'utf8') + 1 : 0;\n\n return 1 + numberBytes + textBytes;\n}\n\n/**\n * Encodes one symbol into a buffer.\n *\n * The buffer is expected to be sized with `symbolByteLength`, so every byte in the range is written:\n * a buffer from `Buffer.allocUnsafe` holds whatever memory it was given, and a byte skipped here\n * would put that memory into the file.\n *\n * @param {Buffer} buffer The buffer.\n * @param {number} offset Where the type byte goes.\n * @param {number} kind The type byte.\n * @param {number|null} number The numeric half, unused for kind 4.\n * @param {string|null} text The text, unused for kinds 1 and 2.\n * @return {number} The offset after the symbol.\n */\nexport function writeSymbol(buffer, offset, kind, number, text) {\n buffer[offset++] = kind;\n\n if (kind === 1 || kind === 5) {\n // @ts-ignore - kinds 1 and 5 carry a number\n offset = buffer.writeInt32LE(number, offset);\n } else if (kind === 2 || kind === 6) {\n // @ts-ignore - kinds 2 and 6 carry a number\n offset = buffer.writeDoubleLE(number, offset);\n }\n\n if (kind >= 4) {\n // @ts-ignore - kinds 4, 5 and 6 carry a text\n offset += buffer.write(text, offset, 'utf8');\n buffer[offset++] = 0;\n }\n\n return offset;\n}\n","// @ts-check\n\nimport {DUAL_BRAND, asDual, checkNumber, checkText} from './util/cellRules.js';\n\n/**\n * A Qlik dual value, holding both of its halves: a number, and the text Qlik displays for it.\n *\n * Qlik stores dates, timestamps and formatted numbers this way - the date `1756-01-01` is the number\n * -52593 with that text, and a fare of `4.50` is the number 4.5 with that text. To Qlik the value\n * *is* the number: it sums, sorts and compares by it, and the text belongs to how the field shows it.\n * That is why a read returns a dual as its number by default, and keeps the text with the frame so a\n * write puts it back. Read with `{duals: 'both'}` to get this object instead, for a cell that has to\n * carry both halves on its own - through a worker, or into another frame.\n *\n * It has no `valueOf` and no `toString`, and every implicit conversion throws a `TypeError`: `+`,\n * `-`, `<`, `==` against a primitive, a template literal, `String()`, `Number()`, `new Date()`,\n * `join()` and a default `sort()`. Each of those has to pick one half, and whichever it picked would\n * be wrong somewhere - `new Date(dual)` of a date's serial is a moment in January 1970, and a string\n * comparison of a fare's number is not a comparison of its text. Read `.number` or `.text` instead:\n *\n * ```js\n * const fare = new QvdDual(4.5, '4.50');\n * fare.number + 1; // 5.5\n * fare.text; // '4.50'\n * `${fare}`; // TypeError\n * ```\n *\n * It is plain data: `number` and `text` are own, enumerable, read-only properties, and the object is\n * frozen. So `structuredClone`, `postMessage`, `v8.serialize` and `JSON` all turn it into\n * `{number, text}`, and the writer accepts exactly that shape as a dual, from any copy of this\n * library. `===` compares identity, as for any object.\n */\nexport class QvdDual {\n /**\n * Constructs a dual value.\n *\n * The storage kind is not chosen here. The writer derives it from the number, as Qlik does: an\n * integer inside the int32 range is stored as a dual int, anything else as a dual double.\n *\n * @param {number} number The numeric half. Must be a finite number.\n * @param {string} text The text half. Must be a string with no NUL and no unpaired surrogate.\n * @throws {QvdValidationError} If either half cannot be stored in a QVD. The message names the half.\n */\n constructor(number, text) {\n checkNumber(number, 'The number of a dual value', {half: 'number'});\n checkText(text, 'The text of a dual value', {half: 'text'});\n\n defineHalves(this, number, text);\n }\n\n /**\n * Refuses every implicit conversion. See the class comment for why neither half is a safe answer.\n *\n * The hint JavaScript passes is not used: `'number'`, `'string'` and `'default'` say which\n * conversion ran, not which half the caller meant, and the fix is the same for all three.\n *\n * @return {never}\n * @throws {TypeError} Always.\n */\n [Symbol.toPrimitive]() {\n throw new TypeError(\n `A QvdDual holds two values, ${this.number} and ${JSON.stringify(this.text)}; use .number or .text`,\n );\n }\n\n /**\n * Both halves, so `JSON.stringify` loses neither - and produces the shape the writer accepts back.\n *\n * @return {{number: number, text: string}} The dual as a plain object.\n */\n toJSON() {\n return {number: this.number, text: this.text};\n }\n\n /**\n * How Node's `util.inspect` and `console.log` show a dual.\n *\n * @return {string} For example `QvdDual(4.5, \"4.50\")`.\n */\n [Symbol.for('nodejs.util.inspect.custom')]() {\n return `QvdDual(${this.number}, ${JSON.stringify(this.text)})`;\n }\n\n /** @return {string} `'QvdDual'`, for `Object.prototype.toString`. */\n get [Symbol.toStringTag]() {\n return 'QvdDual';\n }\n\n /**\n * Whether a value is a dual cell: a `QvdDual` from any copy of this library, or a plain object whose\n * own enumerable keys are exactly `number` and `text`, which is what a clone of one becomes.\n *\n * Recognition only. The halves are checked when the value is written.\n *\n * @param {any} value Any value.\n * @return {boolean} True for a dual cell.\n */\n static isDual(value) {\n return asDual(value) !== null;\n }\n}\n\n// On the prototype and not enumerable, so it is never copied: a clone is recognised by its shape,\n// and a copy of this class loaded elsewhere by the same key.\nObject.defineProperty(QvdDual.prototype, DUAL_BRAND, {value: true});\n\n/**\n * Defines a dual's halves as own, enumerable, read-only properties and freezes it.\n *\n * Own and enumerable is the point: those are the properties every clone keeps. A getter on the\n * prototype would clone to `{}`.\n *\n * @param {object} target The object being built.\n * @param {number} number The numeric half.\n * @param {string} text The text half.\n */\nfunction defineHalves(target, number, text) {\n Object.defineProperties(target, {\n number: {value: number, enumerable: true},\n text: {value: text, enumerable: true},\n });\n\n Object.freeze(target);\n}\n\n/**\n * A `QvdDual` for a symbol read from a file, taken as stored.\n *\n * Not validated, because a read reports what the file holds: a damaged file's NaN double reads as\n * NaN, and the writer refuses it if anyone stores it again. Built without calling the constructor\n * rather than by setting a flag the constructor reads, so no state outlives the call - a flag left\n * set by a call that threw would have switched validation off for the next `new QvdDual`.\n *\n * @param {number} number The stored int or double.\n * @param {string} text The stored text.\n * @return {QvdDual} A frozen dual.\n */\nexport function dualFromSymbol(number, text) {\n const dual = Object.create(QvdDual.prototype);\n\n defineHalves(dual, number, text);\n\n return dual;\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Checks an option that is a boolean and nothing else.\n *\n * A truthy string is the reason this refuses rather than coerces: `{atomic: 'false'}` would switch on\n * exactly what the caller asked to switch off, and a write that replaces the file where one was asked\n * to rewrite it - or the other way round - is not something they would find out about until it\n * mattered. The same goes for `{coerceNumericStrings: 1}`, which is where the rule started.\n *\n * `undefined` and `null` both mean \"nothing was said\", and `whenUnset` decides what that means. The\n * two callers read it differently on purpose: a read's `coerceNumericStrings` is off unless asked\n * for, while a write's `atomic` and `fsync` are on unless refused, because a null out of optional\n * configuration or a JSON round trip must not quietly become the way that loses the previous file.\n * `validatePath` reads a null `allowedDir` as the working directory for the same reason.\n *\n * Both callers get the same message and the same context, which is what this exists for: two copies\n * of the rule agreed only for as long as somebody kept them in step.\n *\n * @param {any} value The option as passed.\n * @param {{option: string, file: string, whenUnset: boolean}} about The option's name, the file being\n * read or written, and what an unset option means.\n * @return {boolean} What the option says, or `whenUnset`.\n * @throws {QvdValidationError} If the value is neither a boolean nor unset.\n */\nexport function booleanOption(value, {option, file, whenUnset}) {\n if (value === undefined || value === null) {\n return whenUnset;\n }\n\n if (typeof value !== 'boolean') {\n throw new QvdValidationError(`${option} must be true or false`, {\n option,\n provided: value,\n type: typeof value,\n file,\n });\n }\n\n return value;\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {booleanOption} from './optionTypes.js';\n\n/**\n * A read's row window: where it starts, and how many rows it covers.\n *\n * @typedef {Object} QvdRowWindow\n * @property {number} offset File row the window starts at.\n * @property {number|null} limit Rows in the window, or null for \"to the end of the file\".\n */\n\n/**\n * Checks a value that has to be a non-negative integer.\n *\n * Every one of these ends up inside a `Math.min(value, totalRows)` somewhere downstream, which\n * accepts nonsense silently: a negative value yields a negative row count, NaN makes every\n * comparison false, and a fraction produces a fractional loop bound. Each returns a wrong or\n * empty frame rather than an error.\n *\n * @param {any} value The value to check.\n * @param {string} name The option's name, for the error.\n * @param {string} filePath The file being read, for the error.\n * @return {number} The value.\n * @throws {QvdValidationError} If it is not a non-negative integer.\n */\nexport function requireRowCount(value, name, filePath) {\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {\n throw new QvdValidationError(`${name} must be a non-negative integer`, {\n reason: 'option',\n option: name,\n value,\n provided: value,\n type: typeof value,\n file: filePath,\n });\n }\n\n return value;\n}\n\n/**\n * Normalises a row window from what a caller passed.\n *\n * `maxRows` and `limit` are the same number under two names, and this is the one place that is\n * decided. `maxRows` came first and every released version documents it; `limit` is the spelling\n * that reads correctly beside `offset`, because \"the maximum number of rows\" says nothing about\n * where they start. Neither is deprecated and neither is preferred by the code - they resolve to\n * the same field here, three lines apart, so they cannot drift.\n *\n * Passing both is refused rather than resolved. Any rule for picking a winner - last one wins,\n * the smaller one wins, they have to agree - is a rule a caller has to know, and getting it wrong\n * returns a plausible number of rows rather than an error.\n *\n * @param {number|null|undefined|{offset?: number, limit?: number|null, maxRows?: number|null}} window\n * The window, or a plain row count meaning \"the first N rows\", or null for all of them.\n * @param {string} filePath The file being read, for errors.\n * @return {QvdRowWindow} The normalised window.\n */\nexport function normaliseWindow(window, filePath) {\n if (window === null || window === undefined) {\n return {offset: 0, limit: null};\n }\n\n // The historical spelling: load(5) means the first five rows. Kept exactly, because it is the\n // signature every existing caller uses and `5` and `{offset: 0, limit: 5}` are the same read.\n if (typeof window === 'number') {\n return {offset: 0, limit: requireRowCount(window, 'maxRows', filePath)};\n }\n\n if (typeof window !== 'object' || Array.isArray(window)) {\n throw new QvdValidationError('The row window must be a number, null, or an {offset, limit} object', {\n reason: 'option',\n option: 'limit',\n value: window,\n provided: window,\n type: typeof window,\n file: filePath,\n });\n }\n\n const {offset, limit, maxRows} = window;\n const limitGiven = limit !== undefined && limit !== null;\n const maxRowsGiven = maxRows !== undefined && maxRows !== null;\n\n if (limitGiven && maxRowsGiven) {\n throw new QvdValidationError('maxRows and limit are two names for the same option; pass one of them, not both', {\n reason: 'option',\n option: 'limit',\n value: limit,\n maxRows,\n limit,\n file: filePath,\n });\n }\n\n return {\n offset: offset === undefined || offset === null ? 0 : requireRowCount(offset, 'offset', filePath),\n limit: limitGiven\n ? requireRowCount(limit, 'limit', filePath)\n : maxRowsGiven\n ? requireRowCount(maxRows, 'maxRows', filePath)\n : null,\n };\n}\n\n/**\n * Holds `chunkSize` to the one rule every caller applies: a positive whole number of rows.\n *\n * One definition rather than two. `iterate` and `checkRead` both need it, and the second copy had\n * already drifted - it carried `reason` and `option` in its context where the first did not, so the same\n * mistake was reported two ways depending on which entry point saw it.\n *\n * @param {any} chunkSize What the caller passed.\n * @param {string} filePath The file, for the error.\n * @return {number} The chunk size.\n * @throws {QvdValidationError} If it is not a positive whole number.\n */\nexport function requireChunkSize(chunkSize, filePath) {\n if (typeof chunkSize !== 'number' || !Number.isInteger(chunkSize) || chunkSize <= 0) {\n throw new QvdValidationError('chunkSize must be a positive integer', {\n reason: 'option',\n option: 'chunkSize',\n value: chunkSize,\n provided: chunkSize,\n type: typeof chunkSize,\n file: filePath,\n });\n }\n\n return chunkSize;\n}\n\n/**\n * Resolves a validated window against the rows a file actually declares.\n *\n * One place, because the answer is used for three different things - which bytes to read, which\n * records to decode, and what to charge the memory guard - and any two of them disagreeing is a\n * silent wrong answer rather than an error.\n *\n * The offset is clamped as well as the count. An offset past the end of the file leaves no rows,\n * which is not an error: it is what a paging loop needs in order to stop, the same way\n * `Array.prototype.slice` answers it. But carrying the unclamped offset forward would have the\n * byte arithmetic demand records the file never had - `{offset: 10_000_000}` on a 135-row file\n * asking for a 30MB read of a 7KB file, and reporting the file as truncated.\n *\n * @param {QvdRowWindow} window The validated window.\n * @param {number} totalRows Rows the file's header declares. An unusable value resolves to an\n * empty window, leaving the structural checks downstream to say what is really wrong with it.\n * @return {QvdRowWindow} The window as it applies to this file: `limit` is now a row count rather\n * than a maximum, and `offset` is inside the file.\n */\nexport function resolveWindow(window, totalRows) {\n const rows = Number.isSafeInteger(totalRows) && totalRows > 0 ? totalRows : 0;\n const offset = Math.min(window.offset, rows);\n\n return {\n offset,\n limit: Math.max(0, Math.min(window.limit === null ? Infinity : window.limit, rows - offset)),\n };\n}\n\n/**\n * Checks a requested field list against the fields a file actually has.\n *\n * Refuses an unknown name rather than dropping it. Returning three columns for a four-name\n * request is the failure shape this library keeps designing against - the caller gets a data\n * frame, the shape looks plausible, and the missing column is discovered somewhere else entirely.\n * A duplicate is refused for the same reason: two columns of one name make `at(row, name)` and\n * `select(name)` answer about the first and ignore the second.\n *\n * The order is the caller's, not the file's, because that is what `QvdDataFrame.select()` already\n * does - `select('b', 'a')` returns `[b, a]` - and one library should not have two answers to the\n * same question.\n *\n * @param {Array<any>} fields Every field header in the file, in file order.\n * @param {Array<string>|null} requested Field names the caller asked for, or null for all.\n * @param {string} filePath The file being read, for errors.\n * @return {Array<any>} The selected field headers, in the caller's order.\n * @throws {QvdValidationError} If a name is unknown, repeated, or the list is empty.\n */\nexport function selectFields(fields, requested, filePath) {\n if (requested === null || requested === undefined) {\n return fields;\n }\n\n if (!Array.isArray(requested)) {\n throw new QvdValidationError('fields must be an array of field names', {\n reason: 'option',\n option: 'fields',\n value: requested,\n provided: requested,\n type: typeof requested,\n file: filePath,\n });\n }\n\n const available = fields.map((/** @type {any} */ field) => field['FieldName']);\n\n // A projection of no columns is a frame of N empty rows, whose shape is [N, 0] and whose data\n // answers nothing. Refusing is more useful than returning it.\n if (requested.length === 0) {\n throw new QvdValidationError('fields must name at least one field', {\n reason: 'option',\n option: 'fields',\n value: requested,\n availableColumns: available,\n file: filePath,\n });\n }\n\n /** @type {Set<string>} */\n const seen = new Set();\n\n return requested.map((name) => {\n if (typeof name !== 'string') {\n throw new QvdValidationError('Field names must be strings', {\n reason: 'option',\n option: 'fields',\n value: name,\n provided: name,\n type: typeof name,\n availableColumns: available,\n file: filePath,\n });\n }\n\n if (seen.has(name)) {\n throw new QvdValidationError(`Field '${name}' is listed twice`, {\n reason: 'option',\n option: 'fields',\n value: name,\n column: name,\n fields: requested,\n file: filePath,\n });\n }\n\n seen.add(name);\n\n const index = available.indexOf(name);\n\n if (index === -1) {\n throw new QvdValidationError(`Column '${name}' does not exist`, {\n reason: 'option',\n option: 'fields',\n value: name,\n column: name,\n availableColumns: available,\n file: filePath,\n });\n }\n\n return fields[index];\n });\n}\n\n/** What a dual symbol can read back as. The first is the default. */\nconst DUAL_MODES = Object.freeze(['number', 'text', 'both']);\n\n/**\n * Checks the `duals` option.\n *\n * A dual is a number with the text Qlik displays for it: the date -52593 shown as `1756-01-01`, the\n * fare 4.5 shown as `4.50`. Qlik treats the value as its number - it sums, sorts and compares by it -\n * so `'number'` is the default, and the text is kept with the frame so a write puts it back.\n * `'text'` returns the text instead, and `'both'` a frozen `QvdDual` holding both halves.\n *\n * Refused rather than defaulted when unrecognised: a typo such as `'numbers'` falling back to the\n * default would look like it worked, and the first sign of the mistake would be somewhere else.\n *\n * @param {any} value The option as passed. `undefined` and null mean the default.\n * @param {string} filePath The file being read, for the error.\n * @return {'number'|'text'|'both'} The mode.\n * @throws {QvdValidationError} If the value is not one of the modes.\n */\nexport function normaliseDuals(value, filePath) {\n if (value === undefined || value === null) {\n return 'number';\n }\n\n if (!DUAL_MODES.includes(value)) {\n throw new QvdValidationError(`duals must be one of ${DUAL_MODES.map((mode) => `'${mode}'`).join(', ')}`, {\n reason: 'option',\n option: 'duals',\n value,\n provided: value,\n file: filePath,\n });\n }\n\n return value;\n}\n\n/**\n * Checks the `coerceNumericStrings` option.\n *\n * Off by default. A string symbol is a value stored with no number, and a read that turned the ones\n * spelled like numbers into numbers returned values the file does not hold: `Number()` accepts\n * leading zeros, exponents, hex prefixes and surrounding whitespace, so `'007'` read as 7 and `'0x10'`\n * as 16. On, it is that rule - see `isNumericText` - for callers who relied on it, and the original\n * text is kept in the frame's `storedSymbols`, so a write stores the string again.\n *\n * It applies to every cell a read would return as a string: a string symbol in every `duals` mode, and\n * a dual's text under `{duals: 'text'}`, which reads as the number the dual stores rather than as\n * `Number(text)`.\n *\n * A boolean and nothing else. A truthy string such as `'false'` switching it on would be the opposite\n * of what was asked, with no error to say so.\n *\n * @param {any} value The option as passed. `undefined` and null mean off.\n * @param {string} filePath The file being read, for the error.\n * @return {boolean} Whether to coerce.\n * @throws {QvdValidationError} If the value is not a boolean.\n */\nexport function normaliseCoerceNumericStrings(value, filePath) {\n return booleanOption(value, {option: 'coerceNumericStrings', file: filePath, whenUnset: false});\n}\n\n/**\n * The reader options out of a public `fromQvd`-style options object.\n *\n * Split out so that `QvdDataFrame.fromQvd`, `QvdDataFrame.iterate` and `QvdColumnTable.fromQvd`\n * cannot end up supporting three slightly different option sets. They are three answers to the\n * same file with the same knobs; only the shape of what comes back differs.\n *\n * @param {any} options The caller's options.\n * @return {Object} Options for the `QvdFileReader` constructor.\n */\nexport function readerOptionsFrom(options) {\n return {\n allowedDir: options.allowedDir,\n memorySafetyFactor: options.memorySafetyFactor,\n symbolFilteringThreshold: options.symbolFilteringThreshold,\n fields: options.fields === undefined ? null : options.fields,\n duals: options.duals,\n coerceNumericStrings: options.coerceNumericStrings,\n onProgress: options.onProgress,\n signal: options.signal,\n };\n}\n\n/**\n * The reader options a header-only read can use.\n *\n * A subset of `readerOptionsFrom`, and expressed here beside it rather than hand-built at the call\n * site, because the subset is the interesting part: it is what stops the two drifting silently.\n * `readMetadata` used to construct `{allowedDir}` inline, so `onProgress` and `signal` were\n * accepted by the caller, ignored by the reader, and documented as shared by every entry point -\n * three statements that only stayed consistent for as long as nobody checked.\n *\n * `offset`, `limit`, `maxRows`, `fields`, `duals` and `coerceNumericStrings` are absent because they mean\n * nothing here, not because they were forgotten: a read that stops at the XML header has no rows to\n * window and parses no field's symbols to skip or resolve. They are ignored rather than refused, so that\n * one options object can be passed to `readMetadata` and to a data read without the caller having to\n * strip it.\n *\n * @param {any} options The caller's options.\n * @return {Object} Options for the `QvdFileReader` constructor.\n */\nexport function metadataOptionsFrom(options) {\n return {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n signal: options.signal,\n };\n}\n\n/**\n * The row window out of a public `fromQvd`-style options object.\n *\n * @param {any} options The caller's options.\n * @return {{offset?: number, limit?: number|null, maxRows?: number|null}} The window, unvalidated\n * - `normaliseWindow` does that, once, inside the reader.\n */\nexport function windowFrom(options) {\n return {offset: options.offset, limit: options.limit, maxRows: options.maxRows};\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {checkNumber, checkText, describeType} from './cellRules.js';\n\n/**\n * The stored-symbol record: what a frame keeps so that the cells it shows write back as the symbols\n * they were read from.\n *\n * A cell shows one value. Usually that value is the whole symbol - a pure number, a pure string - but\n * not always: a dual read as its number has a text the cell does not show, a dual read as its text has\n * a number, and a string read as a number has the text it was spelled with. For each field that holds\n * such a symbol the record keeps one entry, and entry `i` says that a cell holding `values[i]` stands\n * for the stored symbol (`numbers[i]`, `texts[i]`):\n *\n * | `numbers[i]` | `texts[i]` | The stored symbol |\n * | --- | --- | --- |\n * | a number | a string | a dual |\n * | null | a string | a pure string - one read as a number |\n * | a number | null | a pure number, recorded because another symbol reads as the same value |\n *\n * The last row is what lets the writer see a collision: when two different symbols read as one value,\n * both are recorded, and the writer refuses that value rather than guess which symbol a cell meant.\n *\n * It is plain data - arrays of numbers, strings and nulls - so it survives `JSON`, `structuredClone`,\n * `postMessage` and `v8.serialize` whole, and a frame sent elsewhere can be rebuilt with `fromDict`.\n * It is frozen, because every frame derived from a read shares it: a change through one would change\n * what all of them write.\n *\n * @typedef {Object} StoredSymbolsEntry\n * @property {string} field The field the entry describes.\n * @property {ReadonlyArray<number|string>} values What a cell holds for each recorded symbol.\n * @property {ReadonlyArray<number|null>} numbers Each symbol's number, or null for a pure string.\n * @property {ReadonlyArray<string|null>} texts Each symbol's text, or null for a pure number.\n */\n\n/**\n * @typedef {ReadonlyArray<StoredSymbolsEntry>} StoredSymbols\n */\n\n/**\n * Where a reader leaves the record on the header object it returns.\n *\n * `Symbol.for`, so any copy of this library finds it. The property is not enumerable, so the header\n * still deep-equals the one `readMetadata` returns for the same file, and a caller who builds a frame\n * the way the architecture notes show - `new QvdDataFrame(data, columns, df.metadata)` - keeps the\n * record without knowing it exists.\n */\nexport const STORED_SYMBOLS = Symbol.for('qvdjs.storedSymbols');\n\n/**\n * Records this copy of the module has built or validated, so passing one on - to `head()`, `select()`,\n * a chunk of `iterate()` - costs nothing. A WeakSet, so it holds no record alive.\n *\n * @type {WeakSet<object>}\n */\nconst trusted = new WeakSet();\n\n/**\n * Freezes a record the reader built and marks it as needing no validation.\n *\n * A reader's record is taken as the file stores it. A damaged file's NaN double is recorded as NaN,\n * which validation would refuse: a read reports what is there, and the writer refuses the value if\n * anyone stores it again.\n *\n * @param {Array<StoredSymbolsEntry>} entries Entries whose arrays are already frozen.\n * @return {StoredSymbols} The record.\n */\nexport function trustStoredSymbols(entries) {\n const record = Object.freeze(entries);\n\n trusted.add(record);\n\n return record;\n}\n\n/**\n * Leaves a record on a header object, without making it part of what the header enumerates.\n *\n * @param {any} metadata The header object a read returns.\n * @param {StoredSymbols} record The record.\n */\nexport function attachStoredSymbols(metadata, record) {\n if (metadata !== null && typeof metadata === 'object' && Object.isExtensible(metadata)) {\n Object.defineProperty(metadata, STORED_SYMBOLS, {value: record, enumerable: false, configurable: true});\n }\n}\n\n/**\n * Throws a validation error about a record.\n *\n * @param {string} message The message.\n * @param {Object} context The context.\n * @return {never}\n * @throws {QvdValidationError} Always.\n */\nfunction refuse(message, context) {\n throw new QvdValidationError(message, context);\n}\n\n/**\n * A record checked, frozen and safe to write from, or null for none.\n *\n * Every check a writer relies on is made here, once, so a record typed by hand or rebuilt from JSON\n * can be refused with a message rather than producing a file. What it does *not* check is whether two\n * entries make a value ambiguous; the writer works that out for the values a column actually holds,\n * so a record merged from two reads is checked against the cells it is used with.\n *\n * @param {any} record The record, null or undefined.\n * @return {StoredSymbols|null} A frozen record - the same one when it was already trusted, otherwise\n * a frozen copy - or null.\n * @throws {QvdValidationError} If the record is not an array of well-formed entries.\n */\nexport function normaliseStoredSymbols(record) {\n if (record === null || record === undefined) {\n return null;\n }\n\n if (typeof record === 'object' && trusted.has(record)) {\n return record;\n }\n\n if (!Array.isArray(record)) {\n refuse(`storedSymbols must be an array of field entries; got ${describeType(record)}`, {\n option: 'storedSymbols',\n type: typeof record,\n });\n }\n\n /** @type {Set<string>} */\n const fields = new Set();\n\n const entries = record.map((entry, index) => {\n if (entry === null || typeof entry !== 'object' || Array.isArray(entry) || typeof entry.field !== 'string') {\n refuse('Each storedSymbols entry must be an object with a string field name', {entry: index});\n }\n\n const {field, values, numbers, texts} = entry;\n\n if (fields.has(field)) {\n refuse(`storedSymbols lists field '${field}' twice`, {field, entry: index});\n }\n\n fields.add(field);\n\n if (\n !Array.isArray(values) ||\n !Array.isArray(numbers) ||\n !Array.isArray(texts) ||\n values.length !== numbers.length ||\n values.length !== texts.length\n ) {\n refuse(`The values, numbers and texts of the storedSymbols entry for '${field}' must be arrays of one length`, {\n field,\n entry: index,\n });\n }\n\n for (let symbol = 0; symbol < values.length; symbol++) {\n const value = values[symbol];\n const number = numbers[symbol];\n const text = texts[symbol];\n const context = {field, symbol};\n\n if (typeof value !== 'number' && typeof value !== 'string') {\n refuse(`A stored symbol's value must be a number or a string; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n }\n\n if (number !== null) {\n checkNumber(number, \"A stored symbol's number\", context);\n }\n\n if (text !== null) {\n checkText(text, \"A stored symbol's text\", context);\n }\n\n // What each kind of symbol can be read as. A dual reads as one of its halves; a pure string as\n // itself or, coerced, as a number; a pure number only as itself. An entry that says otherwise\n // would write a symbol no read of it could have produced.\n const consistent =\n number !== null && text !== null\n ? sameValueZero(value, number) || value === text\n : number === null && text !== null\n ? value === text || (typeof value === 'number' && Number.isFinite(value))\n : number !== null && sameValueZero(value, number);\n\n if (!consistent) {\n refuse(\n number === null && text === null\n ? 'A stored symbol needs a number or a text'\n : \"A stored symbol's value must be its number or its text\",\n {...context, value, number, text},\n );\n }\n }\n\n return Object.freeze({\n field,\n values: Object.freeze(values.slice()),\n numbers: Object.freeze(numbers.slice()),\n texts: Object.freeze(texts.slice()),\n });\n });\n\n return trustStoredSymbols(entries);\n}\n\n/**\n * The entries of a record for some of its fields, sharing them rather than copying.\n *\n * @param {StoredSymbols|null} record The record.\n * @param {ReadonlyArray<string>} columns The fields to keep.\n * @return {StoredSymbols|null} The narrowed record: the same one when nothing is dropped, an empty one\n * when nothing is kept, and null only when there was none. Never null for a record, because a frame\n * given null takes the one a read left on its header, with entries for every field of the read.\n */\nexport function narrowStoredSymbols(record, columns) {\n if (record === null) {\n return null;\n }\n\n const kept = record.filter((entry) => columns.includes(entry.field));\n\n return kept.length === record.length ? record : trustStoredSymbols(kept);\n}\n\n/**\n * The entry for one field, or null.\n *\n * @param {StoredSymbols|null} record The record.\n * @param {string} field The field.\n * @return {StoredSymbolsEntry|null} The entry.\n */\nexport function storedSymbolsEntry(record, field) {\n if (record === null) {\n return null;\n }\n\n return record.find((entry) => entry.field === field) ?? null;\n}\n\n/**\n * Value-to-text maps for `textAt`, built on first use per entry. Weak, so an entry that is no longer\n * referenced takes its map with it.\n *\n * @type {WeakMap<StoredSymbolsEntry, Map<number|string, string>>}\n */\nconst firstTexts = new WeakMap();\n\n/**\n * Each value of a record entry, mapped to the text a cell holding it stands for.\n *\n * The text of the first symbol holding the value that has one. Symbols are in the order they appear\n * in the file, and a pure number recorded for a collision has no text, so a dual's text wins over it\n * whichever of the two the file stores first. A value no symbol gives a text is not in the map.\n *\n * Built from the last symbol to the first, so an earlier text overwrites a later one and each symbol\n * costs one write rather than a lookup and a write.\n *\n * @param {StoredSymbolsEntry} entry The field's entry.\n * @return {Map<number|string, string>} Value to text.\n */\nexport function firstTextByValue(entry) {\n /** @type {Map<number|string, string>} */\n const byValue = new Map();\n\n for (let index = entry.values.length - 1; index >= 0; index--) {\n const text = entry.texts[index];\n\n if (text !== null) {\n byValue.set(entry.values[index], text);\n }\n }\n\n return byValue;\n}\n\n/**\n * The text a cell stands for, according to a record entry - see `firstTextByValue`.\n *\n * @param {StoredSymbolsEntry} entry The field's entry.\n * @param {number|string} value The cell.\n * @return {string|null} The text, or null when the entry gives the value none.\n */\nexport function storedTextOf(entry, value) {\n let byValue = firstTexts.get(entry);\n\n if (byValue === undefined) {\n byValue = firstTextByValue(entry);\n firstTexts.set(entry, byValue);\n }\n\n return byValue.get(value) ?? null;\n}\n\n/**\n * `SameValueZero`, the equality a Map uses for its keys: `===`, except that NaN equals NaN.\n *\n * @param {any} a One value.\n * @param {any} b The other.\n * @return {boolean} Whether they are the same value.\n */\nexport function sameValueZero(a, b) {\n return a === b || (a !== a && b !== b);\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\n\n/**\n * How many symlinks one path may be followed through before the walk gives up.\n *\n * A chain of dangling links terminates only because the kernel answers ELOOP for a cycle rather\n * than ENOENT, and every caller here reaches this code only after the kernel has already answered\n * ENOENT for the same path. This is the belt to that brace: past this many hops the open() these\n * callers precede would answer ELOOP itself, so stopping costs nothing real, and the walk cannot\n * run away on a filesystem that reports a cycle some other way. 40 is Linux's own MAXSYMLINKS, the\n * most permissive of the platforms here.\n */\nexport const MAX_LINK_HOPS = 40;\n\n/**\n * What `readDanglingLink` returns for a name that is on disk and is not a symlink, so there is\n * nothing to follow.\n */\nexport const NOT_A_LINK = Symbol('not a link');\n\n/**\n * What `readDanglingLink` returns for a symlink whose target it could not read. Callers must decide\n * what that means for them rather than treating it as either of the other two answers: it is a link,\n * so it is not `NOT_A_LINK`, and where it points is unknown, so it is not a path.\n */\nexport const UNREADABLE_LINK = Symbol('unreadable link');\n\n/**\n * Follows one symlink whose target does not exist.\n *\n * `realpath()` answers ENOENT for two different things, and they need opposite treatment:\n *\n * - A name that is not on disk. Whoever asked is about to create it, and the name they gave is the\n * name that will be created.\n * - A symlink pointing at a name that is not on disk. The name *is* on disk - it is the link's\n * target that is missing - and an `open()` of the path follows the link and creates the file at\n * the target, wherever that is.\n *\n * Telling the two apart is what decides both whether a path is inside its sandbox and which file a\n * write replaces. `validatePath` answers both in one walk, and the writer and the reader open what\n * that walk found rather than resolving the path again - see `checkPath` there. The two questions\n * used to be answered by two walks through this one function, which kept their rules alike but still\n * let them reach different files when a link changed between the walks: #247.\n *\n * @param {string} target Path whose `realpath()` or `stat()` answered ENOENT or ENOTDIR.\n * @return {string|typeof NOT_A_LINK|typeof UNREADABLE_LINK} Where the link points, resolved against\n * its own directory, or one of the two sentinels above.\n */\nexport function readDanglingLink(target) {\n /** @type {import('fs').Stats} */\n let link;\n\n try {\n link = fs.lstatSync(target);\n } catch {\n // Not on disk under its own name either, or an ancestor is a file or a dangling link itself.\n // Nothing here to follow.\n return NOT_A_LINK;\n }\n\n if (!link.isSymbolicLink()) {\n // The name is on disk and is not a link, yet the caller's own call could not resolve it: the two\n // disagree, which on a quiet filesystem they cannot. What they can disagree about is a link\n // replaced between them. There is nothing here to follow either way.\n return NOT_A_LINK;\n }\n\n /** @type {string} */\n let destination;\n\n try {\n destination = fs.readlinkSync(target);\n } catch {\n return UNREADABLE_LINK;\n }\n\n if (path.isAbsolute(destination)) {\n return destination;\n }\n\n // A relative target is resolved against the directory the link *physically* lives in, which is\n // what the kernel does: by the time it reads the link it has already resolved every directory it\n // walked through. Resolving against the lexical parent instead is not a near-enough approximation,\n // it is an escape. Given an alias inside allowedDir pointing at a shallower directory inside it -\n // say `<allowed>/deep/sub/alias` -> `<allowed>` - a link reached as `.../alias/link.qvd` lives at\n // `<allowed>/link.qvd`, so `../outside/x` means `<outside>/x` to the kernel and\n // `<allowed>/deep/sub/outside/x` to path.dirname. The first is out of the sandbox and the second\n // is in it, so the check passed a path an in-place write then created outside allowedDir.\n //\n // A parent that cannot be canonicalised leaves the target unknown, which is not the same as there\n // being no link: saying so lets each caller refuse rather than guess.\n try {\n return path.resolve(fs.realpathSync(path.dirname(target)), destination);\n } catch {\n return UNREADABLE_LINK;\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport {QvdSecurityError, QvdValidationError} from '../QvdErrors.js';\nimport {MAX_LINK_HOPS, NOT_A_LINK, UNREADABLE_LINK, readDanglingLink} from './linkTarget.js';\n\n/**\n * Determines whether a resolved path is contained within a resolved base directory, using only\n * string comparison.\n *\n * This is the fallback for when the filesystem cannot answer the question - in practice, when\n * allowedDir does not exist. It cannot see through symlinks and has to guess at case\n * sensitivity, which is exactly why it is not the primary check.\n *\n * Uses path.relative() rather than a string prefix test, so that filesystem roots\n * ('/', 'C:\\', '\\\\server\\share\\') and base directories with a trailing separator are\n * handled correctly. A prefix test appends path.sep to the base, which produces '//'\n * for a root and therefore matches nothing.\n *\n * @param {string} resolvedBaseDir Absolute, resolved base directory.\n * @param {string} resolvedPath Absolute, resolved candidate path.\n * @return {boolean} True if the path is the base directory itself or lies beneath it.\n */\nfunction isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) {\n // Folding is applied on Windows only. It used to cover darwin as well, on the assumption that\n // macOS is always case-insensitive, but macOS supports case-sensitive APFS and HFS+ volumes on\n // which two names differing only in case are genuinely different directories - so folding there\n // let a sibling directory pass the check. The on-disk comparison below settles case correctly\n // by asking the filesystem, which is why this fallback no longer needs to guess for darwin.\n const isCaseInsensitiveFS = process.platform === 'win32';\n const base = isCaseInsensitiveFS ? resolvedBaseDir.toLowerCase() : resolvedBaseDir;\n const target = isCaseInsensitiveFS ? resolvedPath.toLowerCase() : resolvedPath;\n\n const relative = path.relative(base, target);\n\n // '' means the path IS the base directory. A relative path that starts with '..' escapes\n // the base, and an absolute result means the two are on different roots/drives.\n if (relative === '') {\n return true;\n }\n if (path.isAbsolute(relative)) {\n return false;\n }\n return relative !== '..' && !relative.startsWith(`..${path.sep}`);\n}\n\n/**\n * What resolveDeepestExisting returns for a path that must be refused outright rather than handed\n * to the lexical fallback.\n *\n * Falling back is safe for EACCES and ELOOP because the open() that follows fails for the same\n * reason, so letting the path through costs nothing. That argument does not hold for a symlink the\n * walk could not read: the open() would succeed, at whatever the link points at, while the lexical\n * test saw only the link's own name inside allowedDir.\n */\nconst REFUSED = Symbol('refused');\n\n/**\n * What resolveDeepestExisting found.\n *\n * @typedef {Object} DeepestExisting\n * @property {string} deepest Canonical path of the deepest existing ancestor: the target itself when\n * it exists.\n * @property {boolean} exists Whether `deepest` is the target itself rather than an ancestor of it.\n * @property {string} farEnd The name an open() of the target reaches: the target, or the far end of\n * the dangling symlinks it names. It is what a write creates when the target does not exist.\n */\n\n/**\n * Resolves the deepest ancestor of a path that actually exists, following symlinks.\n *\n * A path being written to does not exist yet, and neither may some of its parent directories, so\n * realpath() on the full path would simply fail. Walking up to the first component that does\n * exist gives the deepest point the filesystem can vouch for; anything below it is a name that\n * will be created inside that directory.\n *\n * A component that is a dangling symlink is followed rather than stepped over. See\n * readDanglingLink in ./linkTarget.js for why the difference is what decides whether a write stays\n * in the sandbox.\n *\n * It also reports where the path leads, and not only whether that is inside the sandbox, because\n * the reader and the writer open what this walk found rather than resolving the path a second time.\n * A second resolution is a second answer, and #247 was the reader and the writer each following a\n * symlink swapped in after the first one: the check approved one file and the open reached another.\n *\n * @param {string} target Absolute, lexically resolved path.\n * @return {DeepestExisting|null|typeof REFUSED} What the walk found, null if it could not be\n * determined, or REFUSED for a path that must not reach the lexical test.\n */\nfunction resolveDeepestExisting(target) {\n let current = target;\n let farEnd = target;\n let walkedUp = false;\n /** Whether a link was followed after the walk had started climbing - see below. */\n let followedWhileClimbing = false;\n let hops = 0;\n\n for (;;) {\n try {\n const deepest = fs.realpathSync(current);\n\n // A file that does not exist yet is created at the far end, and the far end is spelled through\n // the directory the walk just resolved: its canonical path, then whatever lay below it. So the\n // name is opened through directories this check resolved rather than through the path again - a\n // symlinked directory that existed at the check is not traversed a second time at the open. That\n // holds only where the walk reached this directory by climbing from the far end; a link followed\n // on the way up leaves the file's directory missing, so the open fails whatever is said here.\n const canonicalFarEnd =\n walkedUp && !followedWhileClimbing ? path.join(deepest, path.relative(current, farEnd)) : farEnd;\n\n return {deepest, exists: !walkedUp, farEnd: canonicalFarEnd};\n } catch (error) {\n const code = /** @type {{code?: string}} */ (error)?.code;\n\n // ENOENT: this component does not exist. ENOTDIR: an ancestor is a file, so nothing below\n // it can exist either. Both mean \"keep walking up\". Anything else (EACCES, ELOOP) means the\n // filesystem cannot answer, and the caller falls back to the lexical test - which is safe,\n // because an open() on the same path is about to fail for the same reason.\n if (code !== 'ENOENT' && code !== 'ENOTDIR') {\n return null;\n }\n\n // Unless the component is a dangling symlink, which answers ENOENT while being very much on\n // disk. Stepping up past it would judge the link's own name rather than its target.\n const followed = readDanglingLink(current);\n\n if (followed === UNREADABLE_LINK) {\n return REFUSED;\n }\n\n if (followed !== NOT_A_LINK) {\n if (++hops > MAX_LINK_HOPS) {\n return REFUSED;\n }\n\n current = followed;\n\n // Only a link at the end of the path moves the file. One met on the way up - a directory\n // that is a dangling link - leaves the file with no directory to be created in, so an\n // open() of it fails whatever this says, and the far end stays where it was.\n if (walkedUp) {\n followedWhileClimbing = true;\n } else {\n farEnd = followed;\n }\n\n continue;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n walkedUp = true;\n current = parent;\n }\n }\n}\n\n/**\n * Determines whether a path is contained within a base directory by asking the filesystem.\n *\n * Both sides are resolved through symlinks and then compared by identity - device and inode -\n * rather than by name, walking up from the target until the base is found or the root is reached.\n * That settles two questions a string comparison cannot:\n *\n * - Symlinks. A link inside allowedDir pointing outside it resolves to its target, so it is\n * rejected. A lexical check sees only the link's own name, still under allowedDir, and lets it\n * through - which meant arbitrary read via the reader and arbitrary overwrite via the writer.\n * - Dangling symlinks. A link whose target does not exist yet is followed to where it points\n * rather than resolved, because realpath() cannot tell that name from one that is simply absent.\n * Both answer ENOENT, and treating the link as absent judged its parent instead of its target -\n * which let an in-place write create the file outside allowedDir.\n * - Case. On a case-insensitive volume 'Qvd' and 'qvd' are one directory and share an inode; on a\n * case-sensitive volume they are two directories with different inodes. Comparing identity gets\n * both right without inferring anything from process.platform, which is what the old code did\n * and got wrong on case-sensitive macOS volumes.\n *\n * Identity is read with {bigint: true}, and that is load-bearing. On Windows the inode is the\n * 64-bit NTFS file ID, with the MFT record number in the low 48 bits and a reuse counter in the\n * high 16, so any record whose counter has reached 32 has an ID of 2^53 or more. As a Number that\n * loses its low bits, and two directories created one after the other - adjacent records with the\n * same counter - can round to the same value. The sibling then compares equal to the base, and\n * every path under it passes as contained, symlink or not. It is the likeliest explanation of CI\n * run 35339008309, where a Windows runner accepted every path under a sibling of allowedDir.\n *\n * A check on a path is only as good as the open that follows it, because the path can change in\n * between. So this also returns what it approved: the file an open of the path reaches, and that\n * file's identity when it exists. `openChecked` in ./openChecked.js opens exactly that file, refuses\n * a symlink swapped in at its name, and compares the descriptor it gets with this identity, which is\n * what #247 was missing. What no check made through Node's API can cover is a directory further up\n * the path swapped for a symlink: see `openChecked` for that residual, and why it remains.\n *\n * @param {string} resolvedBaseDir Absolute, lexically resolved base directory.\n * @param {string} resolvedPath Absolute, lexically resolved candidate path.\n * @return {{contained: boolean, target: string, stats: import('fs').BigIntStats|null}|null} Whether\n * the path is contained, the file an open of it reaches, and that file's stats if it exists - or\n * null when the filesystem could not answer.\n */\nfunction isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {\n /** @type {import('fs').BigIntStats} */\n let baseStat;\n\n try {\n // The base has to exist to be identified. If it does not, there is nothing on disk to compare\n // against and the lexical fallback is all that is left.\n baseStat = fs.statSync(fs.realpathSync(resolvedBaseDir), {bigint: true});\n } catch {\n return null;\n }\n\n const found = resolveDeepestExisting(resolvedPath);\n\n // A dangling symlink the walk could not read. The lexical fallback would judge the link's own\n // name, which is inside allowedDir, while the open() still went wherever the link points, so\n // there is nothing safe to fall back to.\n if (found === REFUSED) {\n return {contained: false, target: resolvedPath, stats: null};\n }\n\n if (found === null) {\n return null;\n }\n\n // An existing file is opened by its canonical path, whose last component is not a symlink - which\n // is what lets the open refuse one that appears there afterwards. A file that does not exist yet is\n // created at the far end of any dangling links, as an open() of the path itself would create it.\n const target = found.exists ? found.deepest : found.farEnd;\n /** @type {import('fs').BigIntStats|null} */\n let stats = null;\n let current = found.deepest;\n\n // realpathSync() returns a fully canonical path, so every ancestor of it is canonical too and\n // walking up with dirname() cannot step through a symlink.\n for (let first = true; ; first = false) {\n const ownIdentity = first && found.exists;\n let stat;\n try {\n // The file's own identity is read without following a link at its name. realpathSync() resolved\n // it a moment ago to a name whose last component was not a link, but a link can be swapped in\n // before this line, and stat would then record whatever it points at - outside allowedDir,\n // perhaps - as the file this check approved. An open that follows the same link, which is what\n // Windows does for want of O_NOFOLLOW, would then match that identity and be let through. lstat\n // records the link as the link it is, which no open of its target can match. Only the file\n // itself: the directories above it are compared as they always were.\n stat = ownIdentity ? fs.lstatSync(current, {bigint: true}) : fs.statSync(current, {bigint: true});\n } catch {\n return null;\n }\n\n // The first stat is of the file itself when it exists. It is kept from this walk rather than\n // taken again later, so the identity an open is held to is the identity this check approved.\n if (ownIdentity) {\n stats = stat;\n }\n\n // Both sides are BigInts, so this compares every bit of the ID rather than a rounded double.\n if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {\n return {contained: true, target, stats};\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return {contained: false, target, stats};\n }\n current = parent;\n }\n}\n\n/**\n * A path the containment check approved, and what it approved.\n *\n * @typedef {Object} CheckedPath\n * @property {string} path The lexically resolved path, which is what callers report: the path they\n * were given, made absolute.\n * @property {string} base The allowed directory the check was made against, resolved. Held so that a\n * later check of the same path is made against the same directory, whatever the working directory\n * has become since.\n * @property {string} target The file an open of the path reaches: its canonical path when it exists,\n * or the name a write would create. This, and not `path`, is what is opened.\n * @property {import('fs').BigIntStats|null} stats The target's stats as the check found them, or null\n * when it did not exist then. Its `dev` and `ino` are what the opened descriptor is compared with.\n * @property {boolean} onDisk Whether the filesystem decided containment. False when it could not -\n * allowedDir does not exist, or a component refused to resolve - and the lexical fallback did. The\n * target is then only the lexical path, so there is nothing for an open to be held to.\n */\n\n/**\n * Checks that a path stays inside the allowed directory, and says what it found there.\n *\n * Containment is decided by the filesystem wherever it can be: both paths are resolved through\n * symlinks and compared by device and inode. That covers symlink escapes and case sensitivity,\n * neither of which a string comparison can get right. When the base directory does not exist,\n * there is nothing to compare against and a lexical check is used instead.\n *\n * To permit access to an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on\n * Windows). There is deliberately no separate \"disable the check\" value: a null or empty\n * allowedDir falls back to the current working directory, so a caller that accidentally\n * passes one still gets the restriction rather than silently losing it.\n *\n * The answer is a path and the file it reaches, and the second half is the one that matters to the\n * reader and the writer: they open `target` through `openChecked`, which holds the open to what this\n * approved. Opening `path` instead would resolve it again, and a second resolution can reach a\n * different file from the first.\n *\n * @param {string} filePath The path to check.\n * @param {string|null} [allowedDir] Optional allowed directory path. Defaults to the current\n * working directory to prevent path traversal attacks.\n * @throws {QvdValidationError} If filePath is not a non-empty string, or allowedDir is not a\n * string, null or undefined.\n * @throws {QvdSecurityError} If path traversal is detected.\n * @return {CheckedPath} What was checked, and what it reaches.\n */\nexport function checkPath(filePath, allowedDir) {\n // Validate argument types up front, so callers get a typed error instead of a bare TypeError\n // from deep inside the function (e.g. 'filePath.includes is not a function').\n if (typeof filePath !== 'string' || filePath.length === 0) {\n throw new QvdValidationError('filePath must be a non-empty string', {\n provided: filePath,\n type: typeof filePath,\n });\n }\n\n if (allowedDir !== undefined && allowedDir !== null && typeof allowedDir !== 'string') {\n throw new QvdValidationError('allowedDir must be a string, null or undefined', {\n provided: allowedDir,\n type: typeof allowedDir,\n });\n }\n\n // Check for null bytes which can be used in path traversal attacks\n if (filePath.includes('\\0')) {\n throw new QvdSecurityError('Path traversal detected: Null byte in path', {\n path: filePath,\n reason: 'null_byte',\n });\n }\n\n const resolvedPath = path.resolve(filePath);\n\n // Default to the current working directory when no allowed directory is specified. This\n // prevents path traversal attacks by ensuring files can only be accessed within the CWD\n // or a more restrictive allowed directory.\n //\n // null and '' deliberately fall back to the CWD rather than meaning \"no restriction\":\n // callers routinely produce them from optional config or a JSON round trip, and silently\n // dropping the sandbox in that case would be a security hole. A caller that genuinely wants\n // an entire volume passes its root ('/' or 'C:\\\\'), which the containment test supports.\n const baseDir = allowedDir || process.cwd();\n const resolvedBaseDir = path.resolve(baseDir);\n\n const onDisk = isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath);\n const contained = onDisk === null ? isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) : onDisk.contained;\n\n if (!contained) {\n throw new QvdSecurityError('Path traversal detected: Access denied', {\n path: filePath,\n resolvedPath,\n allowedDir: resolvedBaseDir,\n reason: 'outside_allowed_directory',\n // Says which check refused, so a rejection of a path that looks contained is traceable to\n // a symlink or a case difference rather than looking like a bug.\n check: onDisk === null ? 'lexical' : 'filesystem',\n });\n }\n\n if (onDisk === null) {\n return {path: resolvedPath, base: resolvedBaseDir, target: resolvedPath, stats: null, onDisk: false};\n }\n\n return {path: resolvedPath, base: resolvedBaseDir, target: onDisk.target, stats: onDisk.stats, onDisk: true};\n}\n\n/**\n * Validates that a file path stays inside the allowed directory.\n *\n * `checkPath` without the half that says what the path reaches, for a caller that only needs the\n * answer. The reader and the writer do not use it: see `checkPath` for why.\n *\n * @param {string} filePath The path to validate.\n * @param {string|null} [allowedDir] Optional allowed directory path. Defaults to the current\n * working directory to prevent path traversal attacks.\n * @throws {QvdValidationError} If filePath is not a non-empty string, or allowedDir is not a\n * string, null or undefined.\n * @throws {QvdSecurityError} If path traversal is detected.\n * @return {string} The resolved absolute path. This is the lexically resolved path, not the\n * canonical one, so callers see the path they asked for.\n */\nexport function validatePath(filePath, allowedDir) {\n return checkPath(filePath, allowedDir).path;\n}\n","// @ts-check\n\nimport {QvdIOError} from '../QvdErrors.js';\n\n/**\n * Whether an error is the operating system's refusal of a file-system call.\n *\n * Node reports those as system errors, which name the call in `syscall` and the reason in `code`:\n * `ENOENT`, `EISDIR`, `EACCES`, `EBUSY`. Nothing else carries a `syscall` - not this library's own\n * errors, and not a `TypeError` from a bug. Nor did the `RangeError` a file handle's `readFile` raised\n * for a file above 2 GiB, a limit of Node's rather than a failure of the disk; a read no longer calls\n * it (#122).\n *\n * Tested by shape rather than with `instanceof Error`, because a system error is made in Node's own\n * realm, and a runner that sandboxes modules - Jest does - has a different `Error` to compare it with.\n *\n * @param {unknown} error What was thrown.\n * @return {boolean} True for a system error.\n */\nfunction isSystemError(error) {\n const candidate = /** @type {{code?: unknown, syscall?: unknown}|null} */ (error);\n\n return (\n candidate !== null &&\n typeof candidate === 'object' &&\n typeof candidate.syscall === 'string' &&\n typeof candidate.code === 'string'\n );\n}\n\n/**\n * A failed file-system call as a `QvdIOError`, or anything else unchanged.\n *\n * Every one of these used to reach the caller as Node's own error (#126), so a caller's\n * `catch (error) { if (error instanceof QvdError) ... }` saw a corrupt file but not a missing one.\n * The system code moves to `context.code` rather than being lost, and Node's error is kept whole as\n * `cause`.\n *\n * The message ends with Node's own - `ENOENT: no such file or directory, open '/data/sales.qvd'` -\n * so a log that prints only messages still names the code, and a search for it still finds the line.\n *\n * @param {unknown} error What the call threw.\n * @param {string} file The QVD file being read or written.\n * @param {'read'|'write'} direction Which of the two, for the message.\n * @return {unknown} A `QvdIOError` whose `cause` is `error`, if the operating system raised it;\n * otherwise `error` itself.\n */\nexport function asIoError(error, file, direction) {\n if (!isSystemError(error)) {\n return error;\n }\n\n const {message, syscall, code} = /** @type {{message: string, syscall: string, code: string}} */ (error);\n\n return new QvdIOError(\n `Could not ${direction} the QVD file: ${message}`,\n {file, operation: syscall, code},\n {cause: error},\n );\n}\n\n/**\n * A `.catch()` handler that rethrows a failed file-system call as a `QvdIOError`.\n *\n * Attached to each call rather than wrapped around the method that makes them, because those methods\n * also run code that is not a file-system call: a caller's `onProgress`, and `signal.throwIfAborted()`,\n * which throws whatever reason the caller aborted with. A system error thrown from either belongs to\n * the caller, and reporting it as a failure to read the QVD file would send them to the wrong place.\n *\n * @param {string} file The QVD file being read or written.\n * @param {'read'|'write'} direction Which of the two, for the message.\n * @return {(error: unknown) => never} The handler.\n */\nexport function rethrowAsIoError(file, direction) {\n return (error) => {\n throw asIoError(error, file, direction);\n };\n}\n\n/**\n * Runs `use` on an open file, then closes it - reporting a failed close only when `use` succeeded.\n *\n * `finally { await handle.close() }`, which this replaced, lets a close that fails replace the error\n * `use` was already throwing, and that error is the one that says what went wrong: a truncated file\n * read as a `QvdCorruptedError`, or a write the disk refused with `ENOSPC`, came back as an `EIO`\n * from the close. A close can fail on the same path for the same reason - a network share reports a\n * write's deferred error when the file is closed - so this is not only a corner case. The file is\n * still closed on that path; only the close's own failure is dropped. A read is one handle through\n * this, header and all, so the rule holds for every read as well as every write.\n *\n * When `use` succeeded, a failed close is the only news and is reported: after a write it can mean\n * the data never reached the disk.\n *\n * @template T\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {(error: unknown) => never} failed What a failed close is rethrown through - the\n * `rethrowAsIoError` handler of the read or write it belongs to.\n * @param {() => Promise<T>} use The work to do with the file.\n * @return {Promise<T>} What `use` returned.\n */\nexport async function closeAfter(handle, failed, use) {\n let result;\n\n try {\n result = await use();\n } catch (error) {\n await handle.close().catch(() => {});\n throw error;\n }\n\n await handle.close().catch(failed);\n\n return result;\n}\n","// @ts-check\n\nimport fs from 'fs';\n// Node's assert, for an invariant a bug in this library would violate - as the reader and the writer\n// use it - never for input.\nimport assert from 'assert';\nimport {QvdSecurityError} from '../QvdErrors.js';\n\n/**\n * `O_NOFOLLOW` where the platform defines it, and nothing where it does not.\n *\n * It makes an open() of a symlink fail with ELOOP instead of following it. POSIX defines it; Windows\n * does not, and `fs.constants.O_NOFOLLOW` is undefined there, so there the open follows a link and\n * it is the identity check that refuses what it reaches.\n */\nexport const NOFOLLOW = fs.constants.O_NOFOLLOW ?? 0;\n\nconst {O_RDONLY, O_WRONLY} = fs.constants;\n\n/**\n * What an open answers when the name it was given has become a symlink since it was checked. ELOOP\n * on Linux and macOS; EMLINK is how the BSDs answer the same thing.\n */\nconst BECAME_A_LINK = new Set(['ELOOP', 'EMLINK']);\n\n/**\n * How the file at a checked path differs from what the check approved.\n *\n * @typedef {'became_a_symlink'|'replaced'|'appeared'} Change\n */\n\n/** What each change says in a message. @type {Record<Change, string>} */\nconst DESCRIPTIONS = {\n became_a_symlink: 'the file became a symbolic link after it was checked',\n replaced: 'the file was replaced by a different one after it was checked',\n appeared: 'a file appeared at the path after it was checked',\n};\n\n/**\n * The error for a file that is not the file the containment check approved.\n *\n * A `QvdSecurityError` like any other containment refusal, with a reason of its own, because what\n * it reports is the same thing a refused path is: an open that would have reached a file the\n * sandbox did not approve. `change` says how, for a caller that logs it.\n *\n * @param {import('./validatePath.js').CheckedPath} checked What was checked.\n * @param {Change} change How the file differs from it.\n * @return {QvdSecurityError} The error.\n */\nfunction changedAfterCheck(checked, change) {\n return new QvdSecurityError(`Path traversal detected: ${DESCRIPTIONS[change]}`, {\n path: checked.path,\n resolvedPath: checked.target,\n allowedDir: checked.base,\n reason: 'changed_after_check',\n change,\n });\n}\n\n/**\n * Opens the file a checked path reaches, and holds the open to what the check approved.\n *\n * `checkPath` decides containment on a path, and a path can change between that decision and the\n * open that follows it - #247, a symlink swapped in after the check and followed by the open. So the\n * open is made on the file the check resolved rather than on the path, and two things hold it\n * there:\n *\n * - **`O_NOFOLLOW`.** The check resolved the file to its canonical path, whose last component was\n * not a symlink. One that is now is refused rather than followed.\n * - **Identity.** A file that existed at the check is compared with the descriptor by device and\n * inode, so a file replaced by another - or, where there is no `O_NOFOLLOW`, a symlink followed to\n * another - is refused. The comparison is of the descriptor, not of a second stat of the path:\n * a second stat would be a second resolution, and could be answered by a different file. And a read\n * of a name the check found empty that opens anyway is refused too: there is no identity to compare\n * it with, and what appeared could be a link to anywhere - which, without `O_NOFOLLOW`, the open\n * has already followed. The read would have failed with ENOENT a moment earlier.\n *\n * A rewrite is truncated here and only here, once the descriptor is known to be the right file.\n * `'w'` truncates as it opens, which would empty whatever the open reached before anything could\n * check that it was the file approved.\n *\n * A rewrite is only ever of a file that existed at the check, because only then is there an identity\n * to hold the open to. A write to a name nothing is at yet never comes here: the writer builds the\n * file beside the name and renames it there, in either mode, because a rename replaces a name rather\n * than following a link at it. An open that creates cannot promise that - on Windows even `O_EXCL`\n * follows a dangling symlink planted at the name, and creates the file wherever it points.\n *\n * What this does not cover, and nothing reached through Node's API can: a *directory* further up the\n * path swapped for a symlink after the check. The open resolves every directory it passes through,\n * and closing that needs `openat()` one component at a time with `O_NOFOLLOW`, which Node does not\n * expose. Nor, without `O_NOFOLLOW`, can Windows refuse a swapped-in link before the open has\n * followed it: the identity check refuses what it reached, but only after the open.\n *\n * Without an on-disk answer from the check - allowedDir did not exist, or the path would not resolve\n * - there is nothing to hold the open to, and it is made as it always was.\n *\n * @param {import('./validatePath.js').CheckedPath} checked What `checkPath` approved.\n * @param {'read'|'rewrite'} purpose Whether the file is read, or rewritten in place.\n * @param {(error: unknown) => never} failed The read's or write's `rethrowAsIoError` handler, for\n * everything that is the operating system's refusal rather than a change.\n * @param {{nofollow?: number}} [platform] `nofollow` is `NOFOLLOW` unless a test supplies another.\n * @return {Promise<import('fs/promises').FileHandle>} The open file. The caller closes it.\n * @throws {QvdSecurityError} If the file is not the one the check approved.\n */\nexport async function openChecked(checked, purpose, failed, {nofollow = NOFOLLOW} = {}) {\n assert(purpose === 'read' || checked.stats !== null, 'A rewrite in place is of a file that exists.');\n\n const noFollow = checked.onDisk ? nofollow : 0;\n const flags = (purpose === 'rewrite' ? O_WRONLY : O_RDONLY) | noFollow;\n\n /** @type {import('fs/promises').FileHandle} */\n let handle;\n\n try {\n handle = await fs.promises.open(checked.target, flags);\n } catch (error) {\n const {code} = /** @type {{code?: string}} */ (error) ?? {};\n\n if (checked.onDisk && noFollow !== 0 && code !== undefined && BECAME_A_LINK.has(code)) {\n throw changedAfterCheck(checked, 'became_a_symlink');\n }\n\n return failed(error);\n }\n\n const stats = checked.stats;\n\n if (stats === null) {\n if (checked.onDisk) {\n await handle.close().catch(() => {});\n throw changedAfterCheck(checked, 'appeared');\n }\n\n return handle;\n }\n\n try {\n const opened = await handle.stat({bigint: true}).catch(failed);\n\n if (opened.dev !== stats.dev || opened.ino !== stats.ino) {\n throw changedAfterCheck(checked, 'replaced');\n }\n\n // Only a regular file: O_TRUNC does nothing to a device or a FIFO, and ftruncate refuses one.\n if (purpose === 'rewrite' && stats.isFile()) {\n await handle.truncate(0).catch(failed);\n }\n } catch (error) {\n // The error on its way out says what went wrong; a close that fails as well is not news.\n await handle.close().catch(() => {});\n throw error;\n }\n\n return handle;\n}\n","// @ts-check\n\nimport crypto from 'crypto';\nimport fs from 'fs';\nimport path from 'path';\nimport {setTimeout as wait} from 'timers/promises';\n\n/**\n * The longest file name the usual filesystems accept, in bytes - ext4, APFS, HFS+, XFS, NTFS and SMB\n * all stop at 255. Bytes rather than characters: the limit is on the encoded name, so a name of\n * accented or CJK characters reaches it sooner than its length suggests.\n */\nconst MAX_NAME_BYTES = 255;\n\n/**\n * Keeps at most `budget` bytes of a name, cutting whole characters.\n *\n * `Buffer.prototype.subarray` would cut in the middle of a multi-byte character and leave a\n * replacement character in the name, so the characters are counted instead - `for...of` walks code\n * points, which keeps a surrogate pair together as well.\n *\n * @param {string} name The name to shorten.\n * @param {number} budget How many bytes of it may be kept.\n * @return {string} As much of the start of it as fits.\n */\nfunction firstBytesOf(name, budget) {\n if (Buffer.byteLength(name) <= budget) {\n return name;\n }\n\n let kept = '';\n let bytes = 0;\n\n for (const character of name) {\n const size = Buffer.byteLength(character);\n\n if (bytes + size > budget) {\n break;\n }\n\n kept += character;\n bytes += size;\n }\n\n return kept;\n}\n\n/**\n * The temporary file a write builds before it replaces the destination.\n *\n * It sits in the destination's own directory, because a rename is only atomic within one filesystem\n * and a temporary directory can be on another. Three things about the name are deliberate:\n *\n * - **It does not end in `.qvd`.** A Qlik load that names a folder rather than a file -\n * `LOAD * FROM [lib://data/*.qvd] (qvd)` - would otherwise pick a half-written one up as a table.\n * - **It says what left it.** A process killed part-way through a write cannot remove its temporary\n * file, so one can survive beside the QVD, and whoever finds it should be able to tell what wrote\n * it and that it was never meant to last.\n * - **It is random, and opened with `'wx'`.** Two processes writing the same QVD never share one, and\n * a name planted in advance - a symlink out of the allowed directory, say - is not written through.\n *\n * The destination's own name is kept only as far as it fits. The marks above add 27 bytes, and a file\n * name may be 255, so a QVD named with 229 or more would otherwise have been given a temporary file\n * the filesystem refuses outright: `toQvd()` failed with ENAMETOOLONG on a name it had written\n * happily until 2.0.0 - measured at 235 characters, where the in-place write still succeeded. What is\n * cut is the end, so the part that identifies the file survives.\n *\n * @param {string} target The file to be replaced.\n * @return {string} The temporary file to build it in.\n */\nexport function temporaryPathFor(target) {\n const marks = `.qvdjs-${crypto.randomBytes(8).toString('hex')}.tmp`;\n const name = `${firstBytesOf(path.basename(target), MAX_NAME_BYTES - marks.length)}${marks}`;\n\n return path.join(path.dirname(target), name);\n}\n\n/**\n * What Windows answers while something else has the file open. POSIX has no equivalent: there EPERM\n * and EACCES are about the directory's permissions, which waiting does not change.\n */\nconst IN_USE = new Set(['EPERM', 'EACCES', 'EBUSY']);\n\n/**\n * How long to wait before each further attempt, in milliseconds - seven attempts within two thirds of\n * a second. Long enough for a scanner to let go of a file it opened when this write closed it, and\n * short enough that a file genuinely held open still fails while the caller is watching.\n */\nconst RETRY_DELAYS = [10, 20, 40, 80, 160, 320];\n\n/**\n * Runs a file-system call, retrying on Windows while it answers that the file is in use.\n *\n * Two kinds of program hold a QVD open briefly without anyone asking them to: a virus scanner or an\n * indexer opening the file this write has just closed, and Qlik Sense reading the one it is about to\n * replace. Neither keeps it for long. graceful-fs, which npm installs through, retries a rename on\n * Windows for these same codes and for this same reason.\n *\n * The error of the last attempt is the one thrown, so a file that is genuinely held open is still\n * reported as `EPERM` rather than as something about retrying.\n *\n * @template T\n * @param {() => Promise<T>} call The call to make.\n * @param {{platform?: string, delays?: Array<number>}} [options] `platform` and `delays` are taken\n * from the running process unless a test supplies them.\n * @return {Promise<T>} What the call returned.\n */\nasync function retrying(call, {platform = process.platform, delays = RETRY_DELAYS} = {}) {\n for (let attempt = 0; ; attempt++) {\n try {\n return await call();\n } catch (error) {\n const {code} = /** @type {{code?: string}} */ (error) ?? {};\n\n if (platform !== 'win32' || attempt >= delays.length || code === undefined || !IN_USE.has(code)) {\n throw error;\n }\n\n await wait(delays[attempt]);\n }\n }\n}\n\n/**\n * Renames `from` over `to`, retrying while Windows reports either as in use.\n *\n * This is the step that makes a write atomic. On POSIX, and on one NTFS volume, it either replaces the\n * destination with the finished file or leaves it exactly as it was; nothing that reads the path sees\n * a part of one.\n *\n * @param {string} from The finished temporary file.\n * @param {string} to The destination it replaces.\n * @param {{platform?: string, delays?: Array<number>}} [options] As `retrying` takes them.\n * @return {Promise<void>} Resolves once the destination is the new file.\n */\nexport function renameOver(from, to, options) {\n return retrying(() => fs.promises.rename(from, to), options);\n}\n\n/**\n * Removes a temporary file that will not be used, throwing nothing.\n *\n * Every call reaches this from a failure that is already on its way to the caller, and that failure\n * says what went wrong. A temporary file that cannot be removed as well is the lesser news, and\n * throwing here would replace the error that explains the write with one about the tidying up. It is\n * still news, though, so it is reported by the answer rather than by an error: the writer names the\n * file it could not remove in the error it is already throwing.\n *\n * @param {string} file The temporary file.\n * @param {{platform?: string, delays?: Array<number>}} [options] As `retrying` takes them.\n * @return {Promise<boolean>} Whether it is gone.\n */\nexport async function removeTemporary(file, options) {\n try {\n // `rm` with `force` rather than `unlink`, for its one useful difference: a file that is already\n // gone is not an error. Something else can remove a temporary file - a system that sweeps them,\n // or a scanner that quarantines one - and reporting that as a failure to remove it would have the\n // writer name a file the caller cannot find in the error it throws.\n //\n // Its own `maxRetries` is left alone. Retrying is this module's to decide, because the rename\n // faces the same Windows condition and the two have to answer it the same way; `rm` retries a\n // different set of codes, on every platform, for a budget of its own.\n await retrying(() => fs.promises.rm(file, {force: true}), options);\n\n return true;\n } catch {\n return false;\n }\n}\n","// @ts-check\n\nimport {QvdCorruptedError} from '../QvdErrors.js';\n\n/**\n * Largest `BitWidth` a field may declare.\n *\n * A stored index is an offset into the field's symbol table, and it is kept in an `Int32Array`,\n * so it has to fit in a positive 32-bit integer. 31 bits addresses 2,147,483,647 symbols in a\n * single field - orders of magnitude beyond anything the rest of the library will load, since\n * the symbol table for that many values would be terabytes and the memory guard refuses long\n * before. A file declaring more is refused rather than decoded: at 32 bits the top of the range\n * wraps to a negative index, which read back as NULL before #125 - silently wrong values instead of\n * an error, the shape bug #113 was. `decodeIndexColumn` now refuses such an index as well, but the\n * header is where the damage is, so that is where it is named.\n */\nexport const MAX_BIT_WIDTH = 31;\n\n/**\n * Powers of two up to 2^39, the widest window a field can span: at most 7 bits of byte\n * misalignment plus `MAX_BIT_WIDTH`. Every value here is exactly representable as a double, and\n * so is every intermediate the decoder forms, which is why the arithmetic below can use `/` and\n * `%` on Numbers rather than 32-bit bitwise operators - those would overflow at 32 bits.\n */\nconst POW2 = Array.from({length: 41}, (_, exponent) => 2 ** exponent);\n\n/**\n * Where a field's bits sit inside a record.\n *\n * Both directions need this, and they must not derive it separately. Two copies of\n * `(shift + bitWidth + 7) >> 3` that drift apart write files this library cannot read, and\n * nothing throws - the decode simply starts a byte early and every field after the first\n * straddling one is misaligned. That is #113's failure shape pointed the other way, so the\n * derivation lives here and the encoder, the decoder and their tests all call it.\n *\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits; zero means it occupies no bits at all.\n * @return {{byteStart: number, shift: number, byteCount: number}} The field's byte window:\n * where it starts, how far into that byte it begins, and how many bytes it touches (0 when\n * the width is zero, otherwise 1 to 5).\n */\nexport function fieldGeometry(bitOffset, bitWidth) {\n const shift = bitOffset & 7;\n\n return {\n byteStart: bitOffset >>> 3,\n shift,\n byteCount: bitWidth === 0 ? 0 : (shift + bitWidth + 7) >>> 3,\n };\n}\n\n/**\n * Decodes one bit-packed field out of every record of an index table.\n *\n * ## The layout\n *\n * A record is `recordSize` bytes. Numbering its bits `p = 0, 1, 2, ...`, bit `p` is\n * `(byte[p >> 3] >> (p & 7)) & 1` - little-endian, least significant bit of each byte first. A\n * field occupies `bitWidth` consecutive bits starting at `bitOffset`, least significant bit\n * first, and `Bias` is then added to the value read.\n *\n * This is the same layout the previous implementation produced, by a much longer route: it\n * reversed the record's bytes, concatenated their binary spellings into a string of\n * `recordSize * 8` characters, split that into an array of one number per bit, reversed it, then\n * sliced the array per field and summed `bit * Math.pow(2, index)`. Several arrays the length of\n * the record in *bits*, built and discarded for every row, which is where roughly 98% of a full\n * read went.\n *\n * ## Why the arithmetic is not bitwise\n *\n * JavaScript's `<<`, `>>>` and `&` coerce to 32 bits, and a field can span up to 39 bits once\n * byte misalignment is counted. `Math.floor(acc / 2**shift) % 2**bitWidth` is exact for every\n * value this can form, because the widest accumulator is under 2^40 and doubles are exact to\n * 2^53.\n *\n * ## Which indices address something\n *\n * With `bounds`, each index is checked as it is decoded, and the first one that addresses nothing\n * is refused. An index addresses a symbol when it is at least 0 and below the field's symbol count.\n * It is the field's NULL when it equals a negative `bias`, which is stored index 0 under Qlik's -2.\n * Anything else points past the end of the symbols or below their start. Neither Qlik nor this\n * library writes such an index, so it is damage. Unchecked, one past the end read back as\n * `undefined` and one below the start as NULL, and neither threw (#125).\n *\n * The check runs on the exact value, before the `Int32Array` stores it. On the taxi fixture's 34\n * million indices it costs about 9 ms against 368 ms for the decode, where a separate pass over the\n * decoded column cost 32 ms. `validateFieldBitMetadata` has already refused a bias whose indices do\n * not fit in 32 bits, so the store cannot turn a refused index into an accepted one, or the other\n * way round.\n *\n * @param {Buffer|Uint8Array} buffer The index table, starting at the first record.\n * @param {number} recordSize Bytes per record.\n * @param {number} rowCount Number of records to decode.\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits. Zero means the field holds a single\n * distinct value and occupies no bits at all.\n * @param {number} bias Added to every decoded value. Qlik writes -2 for a field containing\n * NULLs, where stored index 0 means NULL and real symbols start at 2.\n * @param {Int32Array} out Destination, at least `rowCount` long.\n * @param {IndexBounds|null} [bounds=null] What an index has to address, and what to name when one\n * does not. Null decodes without checking. The symbol-usage pass does that, because it runs before\n * the symbols are parsed, and the decode that follows checks the same rows.\n * @return {Int32Array} `out`.\n * @throws {QvdCorruptedError} With `bounds`, if an index addresses neither a symbol nor NULL.\n */\nexport function decodeIndexColumn(buffer, recordSize, rowCount, bitOffset, bitWidth, bias, out, bounds = null) {\n // Every index at or above this addresses nothing. Infinity when unchecked, so the one test in the\n // loop below never fires.\n const symbolCount = bounds === null ? Infinity : bounds.symbolCount;\n\n // A single-distinct-value column occupies zero bits, so there is nothing to read: every row\n // holds stored index 0, which is `bias` once the bias is applied. That is a symbol, the NULL\n // marker, or - past the end of the symbols - wrong in every row, so the first is refused.\n if (bitWidth === 0) {\n if (bounds !== null && rowCount > 0 && bias >= symbolCount) {\n refuse(bounds, 0, bias, bias);\n }\n\n out.fill(bias, 0, rowCount);\n return out;\n }\n\n const {byteStart, shift, byteCount} = fieldGeometry(bitOffset, bitWidth);\n\n const divisor = POW2[shift];\n const modulus = POW2[bitWidth];\n\n // byteStart + byteCount is at most recordSize - validateFieldBitMetadata has already required\n // bitOffset + bitWidth <= recordSize * 8 - so every read below is inside the record, and the\n // caller has established that `rowCount` whole records are present.\n let base = byteStart;\n\n for (let row = 0; row < rowCount; row++, base += recordSize) {\n let acc = buffer[base];\n\n if (byteCount > 1) acc += buffer[base + 1] * 0x100;\n if (byteCount > 2) acc += buffer[base + 2] * 0x10000;\n if (byteCount > 3) acc += buffer[base + 3] * 0x1000000;\n if (byteCount > 4) acc += buffer[base + 4] * 0x100000000;\n\n const index = (Math.floor(acc / divisor) % modulus) + bias;\n\n // Past the end of the symbols, or below zero without being the NULL marker. `bounds` is tested\n // last, so a valid index costs the two comparisons it fails and nothing more.\n if ((index >= symbolCount || (index < 0 && index !== bias)) && bounds !== null) {\n refuse(bounds, row, index, bias);\n }\n\n out[row] = index;\n }\n\n return out;\n}\n\n/**\n * What a decoded index has to address, and what to name in the error when one does not.\n *\n * @typedef {Object} IndexBounds\n * @property {number} symbolCount The field's symbols. A valid index is below this.\n * @property {string} field The field name.\n * @property {string} file The file.\n * @property {number} firstRow The file row the decode starts at, so the error names the row in the\n * file rather than in a window or a chunk.\n */\n\n/**\n * Refuses an index that addresses neither a symbol nor NULL.\n *\n * @param {IndexBounds} bounds What the index had to address.\n * @param {number} row The row, counted from the start of this decode.\n * @param {number} index The index, bias applied.\n * @param {number} bias The field's bias.\n * @return {never}\n * @throws {QvdCorruptedError} Always.\n */\nfunction refuse(bounds, row, index, bias) {\n throw new QvdCorruptedError('Symbol index out of range', {\n field: bounds.field,\n row: bounds.firstRow + row,\n symbolIndex: index,\n symbolCount: bounds.symbolCount,\n bias,\n file: bounds.file,\n stage: 'parseIndexTable',\n });\n}\n\n/**\n * Writes one bit-packed field into one record. The inverse of `decodeIndexColumn`.\n *\n * Same layout, written the other way: bit `p` of a record is `(byte[p >> 3] >> (p & 7)) & 1`,\n * so a value is shifted left by the field's `shift` and OR-ed across the bytes it touches. The\n * buffer must start zeroed and fields must not overlap, which the caller guarantees by\n * allocating it with `Buffer.alloc` and laying columns out by prefix sum of their widths.\n *\n * Multiplication rather than `<<` for the same reason the decoder divides rather than `>>>`: a\n * field can span 39 bits once misalignment is counted, and JavaScript's bitwise operators stop\n * at 32. Every intermediate here is under 2^40, well inside what a double represents exactly.\n *\n * It takes the geometry rather than a `bitOffset`, so the caller cannot derive the byte window\n * differently from the way `decodeIndexColumn` derives it - see `fieldGeometry`. A zero-width\n * field writes nothing, matching the decoder's zero-width branch, which reads nothing; the\n * first byte used to be written unconditionally, so a `byteCount` of 0 put the value into the\n * next column's bits.\n *\n * @param {Buffer|Uint8Array} buffer The index table being built.\n * @param {number} recordBase Index of the record's first byte.\n * @param {{byteStart: number, shift: number, byteCount: number}} geometry From `fieldGeometry`.\n * @param {number} value The stored index. Must fit in the field's width; the caller checks.\n */\nexport function writeBitField(buffer, recordBase, geometry, value) {\n const {byteStart, shift, byteCount} = geometry;\n\n if (byteCount === 0) {\n return;\n }\n\n const base = recordBase + byteStart;\n const shifted = value * POW2[shift];\n\n buffer[base] |= shifted % 0x100;\n\n if (byteCount > 1) buffer[base + 1] |= Math.floor(shifted / 0x100) % 0x100;\n if (byteCount > 2) buffer[base + 2] |= Math.floor(shifted / 0x10000) % 0x100;\n if (byteCount > 3) buffer[base + 3] |= Math.floor(shifted / 0x1000000) % 0x100;\n if (byteCount > 4) buffer[base + 4] |= Math.floor(shifted / 0x100000000) % 0x100;\n}\n","// @ts-check\n\n/**\n * Numbers a column has just looked up, kept in front of the map the writer finds each cell's symbol in.\n *\n * ## What it is for\n *\n * Both of the writer's passes over the rows ask a `Map` about every cell: the symbol table pass whether the\n * column holds the value yet, the index table pass which symbol it is. On the 1.7M-row taxi fixture that is\n * 68 million probes, and a number's hash is recomputed from its bits on every one of them. Most cells repeat\n * a value the column saw a moment earlier, so each column keeps a small table of the numbers it has looked\n * up: a number found there costs a multiply and a compare, and only the rest are asked of the map.\n *\n * Only plain numbers. A string's hash is cached on the string, so the map answers it without that cost. A\n * dual object is found by identity in a map of its own up to a bound, and past it by its number in the key\n * map; no table fronts either, so a column of fresh dual objects per row gains nothing here.\n *\n * ## Why it cannot change the file\n *\n * A slot is written only on a path that has just asked the map about that same number and had its answer -\n * found there, or just put there - and nothing is ever deleted from the map, nor is a key ever given another\n * symbol. A slot answers only a number `===` to the one it holds, which is the map's own SameValueZero less\n * NaN, and NaN equals nothing. So a hit is a probe that would have answered \"present\", and in the index table\n * pass one that would have returned the index the slot copied from the map. An empty slot holds NaN, so it\n * matches nothing either. No NaN is ever stored: the symbol table pass refuses a NaN cell before the store,\n * and the index table pass stores a number only when the map has an index for it, which it never has for NaN.\n *\n * A table grows empty. Refilling it from every key of the map would pass each through a `Float64Array` store,\n * which is ToNumber: `''` would become 0 and `'42'` 42, and the table would claim numbers the column does not\n * hold. The symbol table pass would skip such a cell, and the index table pass - whose table starts empty\n * and asks the map on every miss - would then refuse the write, or find the symbol later in the table than\n * its first cell puts it. Refilling it from the number keys alone would be safe, and was not worth a walk of\n * the map at every growth.\n *\n * ## The slot\n *\n * `slotOf` multiplies by 2654435761, the prime near 2^32 divided by the golden ratio that Knuth's\n * multiplicative hashing uses. Below 2^53 a double holds every bit of its integer part, and there the low\n * bits of the product are taken: over a run of consecutive integers smaller in magnitude than about 3.39\n * million, where the product stays below 2^53, they are a permutation. Past 2^53 the lowest bits of the\n * product are zeros, more of them the larger it is, so its two 32-bit halves are folded together instead.\n * Chosen by counting, over the numeric columns of the eight largest bundled fixtures and thirteen generated\n * ones, how many cells each of seven candidates sends to the map - see \"The writer's per-cell lookups\" in\n * docs/design/LARGE_FILE_PERFORMANCE_DESIGN.md. No cheap slot suits every column. A multiple of 1024 loses\n * ten of the low bits; a value nearer zero than about 3.8e-10 multiplies to less than one; one large enough\n * multiplies to nothing either half keeps, from about 5e17 in the smallest table to 5e20 in the largest; and\n * steps of one second in a Qlik timestamp come back near the same slot every few seconds in the larger\n * tables. A column the slot does not suit misses, and is switched off below.\n *\n * ## When it is not worth it\n *\n * A table only pays where values repeat. Where they do not, every number costs the table's work and the\n * map's too, and the symbol table pass pays far more for a miss than the index table pass does: measured on\n * 2,000,000-row frames with switching off disabled, the first broke even with between a fifth and three\n * tenths of its numbers missing and the second with about three quarters - see the design record. One cost\n * that was measured is V8's: in Node 24 a `Map` `has` followed by a `set` of a number that has just been\n * multiplied is slower than of one that has not, and every slot function tried paid it. Its cause is not\n * established, nor whether a `get` pays it too.\n *\n * So each table counts, per window of `WINDOW_ROWS` rows, the numbers it was asked about and the misses it\n * is judged on, and is switched off for the rest of its pass when those pass its limit, as a share of the\n * lookups. A window with fewer than `MIN_JUDGED_LOOKUPS` of them carries its counts into the next. A frame of\n * fewer than two windows is judged first at half its rows instead, though never before row\n * `MIN_JUDGED_LOOKUPS`. So a frame of that many rows or fewer is never judged at all, and in any frame the rows\n * after its last judgement are not; on those rows a table that does not pay costs what it costs.\n *\n * - **The symbol table pass** cannot tell whether a new number is the first of many or of none, and every\n * table misses while it fills, so a table's first judged window is held only to `FIRST_WINDOW_MISS_LIMIT` -\n * what a column that never repeats reaches - and later ones to `SYMBOL_PASS_MISS_LIMIT`. A column that\n * misses between the two, as one whose every other number is new does, keeps its table for two windows.\n * Judging sooner was tried, whenever a table was about to grow, and switched off a column of 5,000 values\n * that all appear before any repeats: at its 2,049th number, every lookup had missed.\n * - **The index table pass** knows before it starts how many distinct numbers each column's cell map holds,\n * and how many of its cells are numbers: counted by the symbol table pass's table while it was on, and the\n * rest by `numericCellsAfter` wherever the count could decide whether the column gets a table. It gives no\n * table to a column whose distinct numbers are more than `INDEX_PASS_MISS_LIMIT` of its numeric cells, since\n * first sights alone would miss more than the pass can afford. And it tells a first sight from any other\n * miss: each table keeps a bit per symbol of its column, set when a lookup through it first meets that\n * symbol, whoever made it. A table is judged only on the other misses, and may miss as many as what is left\n * of `INDEX_PASS_MISS_LIMIT` once the column's first sights are taken out. The count of distinct numbers\n * includes numbers the column holds only in duals, so a column with far more of those than plain numbers\n * can be refused a table it would have used.\n *\n * And a table is never larger than its column's numbers can fill. The symbol table pass gives a column its\n * table at its first plain number - `NO_TABLE_YET` stands in until then - so a column of strings or NULLs has\n * none, and the table grows with the column's distinct numbers, up to the power of two at or above the frame's row count and never below\n * `MIN_SLOTS`; the index table pass's is sized from the column's distinct numbers and numeric cells, within\n * its share of the columns that get one. Neither exceeds `MAX_SLOTS`, and all of one pass's tables together\n * hold no more than `TOTAL_SLOTS`: each is taken from a `SlotPool`, a table that cannot be given its slots is\n * not grown or not made, and a table switched off gives them back.\n */\n\n/** Knuth's multiplicative-hashing prime, near 2^32 divided by the golden ratio. Odd, which the permutation needs. */\nconst MULTIPLIER = 2654435761;\n\n/** Below this magnitude a double holds every bit of its integer part. */\nconst EXACT = 2 ** 53;\n\n/** 2^-32, which scales a product's upper half down into the range `| 0` keeps. */\nconst UPPER_HALF = 2 ** -32;\n\n/** Rows per window. Tables are judged at the end of each. */\nexport const WINDOW_ROWS = 16384;\n\n/** The fewest lookups a table is judged on; a window with fewer carries its counts into the next. */\nexport const MIN_JUDGED_LOOKUPS = 1024;\n\n/**\n * The row at which a frame's tables are first judged: the end of the first window, or half the rows of a\n * frame too short for two of them, but no sooner than `MIN_JUDGED_LOOKUPS` rows in.\n *\n * @param {number} rows The frame's rows.\n * @return {number} The row.\n */\nexport function firstJudgementRow(rows) {\n return Math.min(WINDOW_ROWS, Math.max(MIN_JUDGED_LOOKUPS, Math.floor(rows / 2)));\n}\n\n/** The fewest slots a table has. */\nexport const MIN_SLOTS = 64;\n\n/** The most slots a table has: 512 KiB of numbers, and 256 KiB more of indices in the index table pass. */\nexport const MAX_SLOTS = 65536;\n\n/** The most slots one pass's tables hold together: 16 MiB of numbers, and 8 MiB more of indices. */\nexport const TOTAL_SLOTS = 2 ** 21;\n\n/**\n * Slots per distinct number. A direct-mapped table has no second choice for a number whose slot is taken, so\n * two numbers sharing a slot miss each time they alternate; at eight slots per number few of them do.\n */\nconst SLOTS_PER_NUMBER = 8;\n\n/** The share of its lookups a symbol table pass's table may miss before it has been judged. */\nexport const FIRST_WINDOW_MISS_LIMIT = 0.9;\n\n/** The share of its lookups a symbol table pass's table may miss in a later window: the top of its break-even. */\nexport const SYMBOL_PASS_MISS_LIMIT = 0.3;\n\n/** The share of a column's numeric cells the index table pass may miss, first sights included. */\nexport const INDEX_PASS_MISS_LIMIT = 0.75;\n\n/**\n * The slot a number takes in a table of `mask + 1` slots.\n *\n * @param {number} value The number.\n * @param {number} mask The table's size less one; a power of two less one.\n * @return {number} The slot, from 0 to `mask`.\n */\nexport function slotOf(value, mask) {\n const product = value * MULTIPLIER;\n\n return product < EXACT && product > -EXACT ? product & mask : ((product | 0) ^ ((product * UPPER_HALF) | 0)) & mask;\n}\n\n/**\n * The smallest power of two at or above a count, from `MIN_SLOTS` up to at most `most`.\n *\n * @param {number} count The count.\n * @param {number} most The most slots allowed: a power of two from `MIN_SLOTS` to `MAX_SLOTS`.\n * @return {number} The number of slots.\n */\nfunction slotsFor(count, most) {\n let slots = MIN_SLOTS;\n\n while (slots < count && slots < most) {\n slots *= 2;\n }\n\n return slots;\n}\n\n/**\n * The most slots each of `columns` tables may have for all of them to fit in `TOTAL_SLOTS`: a power of two\n * from `MIN_SLOTS` to `MAX_SLOTS`. Past `TOTAL_SLOTS / MIN_SLOTS` columns they do not all fit, and the pool\n * decides which get one.\n *\n * @param {number} columns How many tables share the pass.\n * @return {number} Each one's share.\n */\nexport function shareOf(columns) {\n let slots = MAX_SLOTS;\n\n while (slots > MIN_SLOTS && slots * columns > TOTAL_SLOTS) {\n slots /= 2;\n }\n\n return slots;\n}\n\n/** The slots one pass's tables may still take, of `TOTAL_SLOTS`. */\nexport class SlotPool {\n /**\n * @param {number} [slots] How many there are to give.\n */\n constructor(slots = TOTAL_SLOTS) {\n /** Slots not yet taken. */\n this.left = slots;\n }\n\n /**\n * Takes slots, if there are that many left.\n *\n * @param {number} slots How many.\n * @return {boolean} Whether they were taken.\n */\n take(slots) {\n if (slots > this.left) {\n return false;\n }\n\n this.left -= slots;\n\n return true;\n }\n\n /**\n * Gives slots back.\n *\n * @param {number} slots How many.\n */\n give(slots) {\n this.left += slots;\n }\n}\n\n/**\n * A column's table: the numbers it has looked up, and in the index table pass the index the map gave each.\n */\nexport class SeenNumbers {\n /**\n * @param {number} slots How many slots: a power of two from `MIN_SLOTS` to `MAX_SLOTS`, already taken from\n * `pool`.\n * @param {number} maxSlots The most it may grow to, in the symbol table pass.\n * @param {number} limit The share of its lookups a judged window may miss.\n * @param {SlotPool} pool Where its slots came from, and where they go back when it is switched off.\n * @param {number} [symbols] In the index table pass, the column's symbols, one bit each. -1, the default, in\n * the symbol table pass.\n */\n constructor(slots, maxSlots, limit, pool, symbols = -1) {\n /** Each slot's number, or NaN while it is empty. Only ever compared, never read as data. */\n this.values = new Float64Array(slots).fill(NaN);\n /** Each slot's index from the map, in the index table pass - data, copied from the map's own answer. */\n this.indices = new Int32Array(symbols >= 0 ? slots : 0);\n /**\n * A bit per symbol, in the index table pass, set once a lookup through this table has met it: a miss that\n * meets a symbol whose bit is clear is the first sight of its number. An eighth of a byte per symbol, where\n * the column's maps already hold each one at far greater cost.\n */\n this.met = new Uint32Array(symbols >= 0 ? Math.ceil(symbols / 32) : 0);\n /** The table's size less one, which `slotOf` takes. */\n this.mask = slots - 1;\n /** The most slots it may grow to. */\n this.maxSlots = maxSlots;\n /** The share of its lookups a judged window may miss. */\n this.limit = limit;\n /** Where its slots came from. */\n this.pool = pool;\n /**\n * Numbers looked up through this table since the column's first, carried when it grows. In the symbol\n * table pass that is what tells the index table pass how many of the column's cells are numbers.\n */\n this.cells = 0;\n /** `cells` when the table was last judged, so that the lookups since then are the difference. */\n this.judgedCells = 0;\n /**\n * Of the lookups since then, the misses it is judged on: every miss in the symbol table pass, only misses\n * of numbers met before in the index table pass.\n */\n this.misses = 0;\n /**\n * Whether a window has been judged yet. An index table pass table starts judged: its misses leave first\n * sights out, so it has no filling-up to allow for.\n */\n this.judged = symbols >= 0;\n /**\n * Numbers the symbol table pass put in the map through this table, which size it. Only those: a number\n * that first reached the map in a dual object is found there without being counted, so a column whose\n * numbers all arrive that way first keeps a small table, and is switched off if it misses.\n */\n this.inserted = 0;\n }\n\n /**\n * Remembers a number the symbol table pass has just put in the map, growing the table instead once more\n * than an eighth of its slots would hold distinct numbers - if its pool has the slots. A table the pool\n * cannot grow stops trying, and keeps remembering in the slots it has.\n *\n * @param {number} slot The number's slot, from `slotOf`.\n * @param {number} value The number.\n * @return {SeenNumbers} The table to use from now on: this one, or a larger, empty one.\n */\n remember(slot, value) {\n this.inserted++;\n\n if (this.inserted * SLOTS_PER_NUMBER > this.values.length && this.values.length < this.maxSlots) {\n const slots = Math.min(this.values.length * 4, this.maxSlots);\n\n if (this.pool.take(slots - this.values.length)) {\n // Empty: see the module's note on refilling.\n const grown = new SeenNumbers(slots, this.maxSlots, this.limit, this.pool);\n\n grown.inserted = this.inserted;\n grown.cells = this.cells;\n grown.judgedCells = this.judgedCells;\n grown.misses = this.misses;\n grown.judged = this.judged;\n\n return grown;\n }\n\n this.maxSlots = this.values.length;\n }\n\n this.values[slot] = value;\n\n return this;\n }\n\n /**\n * Marks a symbol met through this table, in the index table pass.\n *\n * @param {number} index The symbol the map answered.\n * @return {boolean} Whether it had been met before; false for a first sight.\n */\n metBefore(index) {\n const word = index >>> 5;\n const bit = 1 << (index & 31);\n const before = (this.met[word] & bit) !== 0;\n\n this.met[word] |= bit;\n\n return before;\n }\n}\n\n/**\n * What a column holds in the symbol table pass until its first plain number: one slot that matches nothing,\n * so that number misses, and the writer gives the column a table of its own there. Shared by every such column,\n * so nothing is ever put in it; the counts a miss adds to it are never read.\n */\nexport const NO_TABLE_YET = new SeenNumbers(1, 1, 0, new SlotPool(1));\n\n/**\n * A table for the symbol table pass, which does not yet know how many distinct numbers a column holds.\n *\n * @param {number} rows The frame's rows. A column holds no more distinct numbers than that, so the table\n * grows no further than the power of two at or above it.\n * @param {SlotPool} pool The pass's pool.\n * @return {SeenNumbers|null} The smallest table, which grows as numbers are put in the map - or null when\n * the pool has no room for it.\n */\nexport function symbolPassTable(rows, pool) {\n return pool.take(MIN_SLOTS)\n ? new SeenNumbers(MIN_SLOTS, slotsFor(rows, MAX_SLOTS), SYMBOL_PASS_MISS_LIMIT, pool)\n : null;\n}\n\n/**\n * How many of a column's cells are plain numbers, when its symbol table pass table stopped counting them part\n * way: switched off, or never given its slots. The rows after that are read only where the count could decide\n * whether the index table pass gives the column a table. Where even every one of them being a number would\n * leave its distinct numbers too many for one, the most there could be answers the same, and no row is read.\n *\n * @param {Array<Array<any>|null|undefined>} data The frame's rows, as the symbol table pass has checked them.\n * @param {number} column The column.\n * @param {{row: number, cells: number}} stopped The row its table stopped counting at, and the numeric cells\n * before it.\n * @param {number} numbers The distinct numbers its cell map holds.\n * @return {number} Its numeric cells: exact wherever the index table pass could give it a table, and otherwise\n * the most there could be.\n */\nexport function numericCellsAfter(data, column, stopped, numbers) {\n const most = stopped.cells + data.length - stopped.row;\n\n if (!indexPassWants(numbers, most)) {\n return most;\n }\n\n let cells = stopped.cells;\n\n for (let row = stopped.row; row < data.length; row++) {\n if (typeof data[row]?.[column] === 'number') {\n cells++;\n }\n }\n\n return cells;\n}\n\n/**\n * How many distinct numbers a cell map holds, for a column whose cell map is not the key map. The keys'\n * types are all that is read: see the module's note on refilling.\n *\n * @param {Map<number|string, number>} map The map from a cell to its index.\n * @return {number} Its number keys.\n */\nexport function numbersIn(map) {\n let numbers = 0;\n\n for (const key of map.keys()) {\n if (typeof key === 'number') {\n numbers++;\n }\n }\n\n return numbers;\n}\n\n/**\n * Whether the index table pass gives a column a table at all.\n *\n * @param {number} numbers The distinct numbers the column's cell map holds.\n * @param {number} cells How many of its cells are plain numbers.\n * @return {boolean} False for a column with no numbers, or so many distinct ones that first sights alone\n * would be more than `INDEX_PASS_MISS_LIMIT` of its lookups.\n */\nexport function indexPassWants(numbers, cells) {\n return numbers > 0 && numbers <= INDEX_PASS_MISS_LIMIT * cells;\n}\n\n/**\n * A table for the index table pass, sized from what the symbol table pass found in the column.\n *\n * @param {number} numbers The distinct numbers the column's cell map holds; `indexPassWants` has said yes.\n * @param {number} cells How many of its cells are plain numbers.\n * @param {number} symbols How many symbols the column has.\n * @param {number} share The column's share of `TOTAL_SLOTS`, from `shareOf`.\n * @param {SlotPool} pool The pass's pool.\n * @return {SeenNumbers|null} The table, or null when the pool has no room for it.\n */\nexport function indexPassTable(numbers, cells, symbols, share, pool) {\n const slots = Math.min(slotsFor(numbers * SLOTS_PER_NUMBER, share), slotsFor(cells, share));\n\n return pool.take(slots)\n ? new SeenNumbers(slots, slots, INDEX_PASS_MISS_LIMIT - numbers / cells, pool, symbols)\n : null;\n}\n\n/**\n * Ends a window of rows. Each table that has been asked about at least `MIN_JUDGED_LOOKUPS` numbers since it\n * was last judged is judged now: switched off for the rest of the pass, giving its slots back, if its misses\n * were more than its share of those lookups - `FIRST_WINDOW_MISS_LIMIT` before its first judgement in the\n * symbol table pass, its own limit otherwise - and started counting again if not. A table asked about fewer\n * keeps counting.\n *\n * @param {Array<SeenNumbers|null>} tables One per column; a table switched off becomes null.\n * @param {number} [row] The row the next window starts at, in the symbol table pass.\n * @param {Array<{row: number, cells: number}|null>|null} [stopped] Where the symbol table pass keeps, for each\n * column whose table it switches off, that row and the numeric cells the table had counted, from which\n * `numericCellsAfter` finishes the count.\n */\nexport function endWindow(tables, row = 0, stopped = null) {\n for (let column = 0; column < tables.length; column++) {\n const table = tables[column];\n\n if (table === null || table === NO_TABLE_YET) {\n continue;\n }\n\n const lookups = table.cells - table.judgedCells;\n\n if (lookups < MIN_JUDGED_LOOKUPS) {\n continue;\n }\n\n if (table.misses > (table.judged ? table.limit : FIRST_WINDOW_MISS_LIMIT) * lookups) {\n tables[column] = null;\n table.pool.give(table.values.length);\n\n if (stopped !== null) {\n stopped[column] = {row, cells: table.cells};\n }\n } else {\n table.judgedCells = table.cells;\n table.misses = 0;\n table.judged = true;\n }\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\nimport xml from 'xml2js';\n// Node's assert, used only for invariants a bug in this library would violate - \"this private\n// method ran after the one that fills the field it reads\". Never for input: everything a caller\n// can get wrong throws a QvdError with a context object instead.\n//\n// #143 read the old Copilot instruction \"use assertions for validation\" as an explanation for\n// these calls. It is not: every one sits after a method that either assigns the field\n// unconditionally or throws, and 3,570 corruption cases across every bundled fixture and every\n// entry point produced no AssertionError. They are checked, and they stay.\nimport assert from 'assert';\nimport {QvdIOError, QvdValidationError} from './QvdErrors.js';\nimport {checkPath} from './util/validatePath.js';\nimport {closeAfter, rethrowAsIoError} from './util/ioErrors.js';\nimport {openChecked} from './util/openChecked.js';\nimport {removeTemporary, renameOver, temporaryPathFor} from './util/replaceFile.js';\nimport {booleanOption} from './util/optionTypes.js';\nimport {fieldGeometry, writeBitField} from './util/bitUtils.js';\nimport {\n asDual,\n checkNumber,\n checkText,\n constructorName,\n describeType,\n isNumericText,\n numberProblem,\n textProblem,\n} from './util/cellRules.js';\nimport {kindOf, symbolByteLength, writeSymbol} from './util/symbolBytes.js';\nimport {firstTextByValue, normaliseStoredSymbols, sameValueZero} from './util/storedSymbols.js';\nimport {\n NO_TABLE_YET,\n SlotPool,\n WINDOW_ROWS,\n endWindow,\n firstJudgementRow,\n indexPassTable,\n indexPassWants,\n numbersIn,\n numericCellsAfter,\n shareOf,\n slotOf,\n symbolPassTable,\n} from './util/seenNumbers.js';\n\n/**\n * @typedef {import('./QvdDataFrame.js').QvdDataFrame} QvdDataFrame\n */\n\n/**\n * Persists a QVD file to disk.\n */\n/**\n * The index of the first character in a text that XML 1.0 cannot hold, even written as a character\n * reference: a C0 control other than tab, line feed and carriage return, or U+FFFE or U+FFFF. NUL is one\n * of them; a surrogate without its pair, the other thing XML cannot hold, is `textProblem`'s to report.\n *\n * @param {string} value The text.\n * @return {number} The index, or -1 when there is none.\n */\nfunction notXmlIndex(value) {\n for (let index = 0; index < value.length; index++) {\n const unit = value.charCodeAt(index);\n\n if ((unit < 0x20 && unit !== 0x09 && unit !== 0x0a && unit !== 0x0d) || unit === 0xfffe || unit === 0xffff) {\n return index;\n }\n }\n\n return -1;\n}\n\n/**\n * Throws unless a text can be written into the XML header.\n *\n * The header is XML, which has no way to write a NUL, a surrogate without its pair or a control\n * character such as U+0001. The builder refused each with a bare `Error: Invalid character in string`,\n * naming neither the field nor the property. A read can produce such a text: the parser accepts a raw\n * control character in the header it reads, so a file carrying one in its table name read without\n * complaint and could not be written back.\n *\n * @param {string} value The text.\n * @param {string} subject What the text is, capitalised, as the message starts.\n * @param {Object} context Where the text came from, merged into the error's context.\n * @throws {QvdValidationError} If the text holds a character the header cannot; `context.position` is\n * its index.\n */\nfunction checkHeaderText(value, subject, context) {\n checkText(value, subject, context);\n\n const position = notXmlIndex(value);\n\n if (position !== -1) {\n const code = value.charCodeAt(position).toString(16).toUpperCase().padStart(4, '0');\n\n throw new QvdValidationError(`${subject} cannot contain U+${code}, which XML cannot hold`, {...context, position});\n }\n}\n\n/**\n * Checks every text in a part of the header: a string, or the strings inside an object or an array, as\n * the XML builder would write them.\n *\n * @param {any} value The value.\n * @param {string} property Its path in the header, such as `Lineage.LineageInfo.Statement`.\n * @param {string} owner What the property belongs to, for the message: `the table`, or a field.\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If a text holds a character the header cannot.\n */\nfunction checkHeaderTexts(value, property, owner, context) {\n if (typeof value === 'string') {\n checkHeaderText(value, `The ${property} of ${owner}`, {...context, property});\n } else if (Array.isArray(value)) {\n value.forEach((item, index) => checkHeaderTexts(item, `${property}[${index}]`, owner, context));\n } else if (value !== null && typeof value === 'object') {\n for (const [key, item] of Object.entries(value)) {\n checkHeaderTexts(item, `${property}.${key}`, owner, context);\n }\n }\n}\n\n/**\n * Checks the field names before a single row is walked.\n *\n * All three of these produced a file rather than an error. A non-string name was written as\n * whatever it stringified to; a duplicate produced two fields of one name, which makes\n * `at(row, name)` and `select(name)` answer about the first and ignore the second - and which\n * broke two-pass symbol filtering, because the usage sets were keyed by name (#181); and an empty\n * name produced a field nothing can address. A name the header cannot hold - see `checkHeaderText` -\n * is refused here too, before the rows rather than after them.\n *\n * @param {Array<any>} columns The field names.\n * @param {string} filePath The file being written, for the error.\n * @throws {QvdValidationError} If a name is not a usable, unique string.\n */\nfunction validateColumnNames(columns, filePath) {\n /** @type {Set<string>} */\n const seen = new Set();\n\n columns.forEach((name, index) => {\n if (typeof name !== 'string' || name.length === 0) {\n throw new QvdValidationError('Field names must be non-empty strings', {\n column: index,\n provided: name,\n type: typeof name,\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n checkHeaderText(name, 'A field name', {column: index, provided: name, file: filePath, stage: 'buildSymbolTable'});\n\n if (seen.has(name)) {\n throw new QvdValidationError(`Field '${name}' appears twice`, {\n column: name,\n columnIndex: index,\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n seen.add(name);\n });\n}\n\n/**\n * Refuses a cell that is neither a number, a string, a dual value nor NULL.\n *\n * Everything refused here previously produced either a raw `TypeError` from deep inside\n * `Buffer.from`, naming neither the field nor the row, or a file. The file cases are the reason\n * this is not merely a nicer error message: `[1, 2]` became `Buffer.from([1, 2])`, so the array was\n * written as the two *bytes* 1 and 2 and read back as two control characters; and a `Date` was\n * written as its full `toString()`, which carries the writing machine's timezone and locale into the\n * data.\n *\n * A `QvdSymbol` is refused too. It carries a storage kind, which the writer derives from the value\n * instead, and a dual symbol built through its factories was never a dual cell anyone could read back.\n * So is an object that only resembles a dual - `{number, text, date}`, or one that inherits the two\n * properties - because storing it as one would discard the rest of it without a word.\n *\n * Numbers and strings are checked in `cellRules`, which is where the other things that used to\n * produce a file are refused: a string containing a NUL, which ends a string symbol early and made\n * `toQvd` produce a file this same library refuses to read; a string containing an unpaired\n * surrogate, which UTF-8 cannot encode, so it was written as U+FFFD and two different strings could\n * become one stored value; and `NaN` or an infinity, which came back as the string `'NaN'` or as the\n * infinity itself.\n *\n * @param {any} value The value.\n * @param {string} column The field it belongs to, for the error.\n * @param {number} row The row it was first seen on, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {never}\n * @throws {QvdValidationError} Always.\n */\nfunction refuseCell(value, column, row, filePath) {\n let resemblesDual = false;\n\n try {\n resemblesDual =\n value !== null &&\n typeof value === 'object' &&\n ('number' in value || 'text' in value || ('intValue' in value && 'stringValue' in value));\n } catch {\n // A revoked Proxy throws from `in`. It resembles nothing.\n }\n\n throw new QvdValidationError(\n `A QVD field holds numbers, strings, dual values and NULL; ${describeType(value)} cannot be written. ` +\n `Convert it first - a Date to new QvdDual(dateToQlikSerial(date), text), the serial and the text Qlik shows, ` +\n `which is how Qlik stores a date; a boolean to -1 and 0, as a Qlik comparison stores it.` +\n (resemblesDual ? ' A dual value is a QvdDual, or an object whose only keys are number and text.' : ''),\n {\n column,\n row,\n type: typeof value,\n constructor: constructorName(value) ?? undefined,\n file: filePath,\n stage: 'buildSymbolTable',\n },\n );\n}\n\n/**\n * How many dual objects a column remembers by identity before it stops adding them: this many, plus\n * two for every symbol the column holds.\n *\n * A read shares one `QvdDual` per symbol between every row that holds it, so remembering each object\n * makes a repeat cost one lookup, as a repeated number does. A caller who builds a fresh object per\n * row would add one entry per row instead - two million rows, two million entries - so past the bound\n * an object is resolved by its number on every row, which costs a validation and a lookup and holds\n * nothing.\n */\nconst OBJECT_MEMO_BASE = 64;\n\n/**\n * One column's symbols while they are collected.\n *\n * `keys` and `texts` are the slots, in first-appearance order: a slot's key is its number or its\n * string, and its text is the text of a dual, or null. `byKey` maps a key to its slot, so one number is\n * one symbol however it arrived - a plain number, a dual object, a cell resolved through the record.\n * `byCell` maps a primitive cell to its slot, and is `byKey` itself unless the field has a record\n * entry that can map a cell to a different key. `byObject` remembers dual objects by identity, up to\n * a bound.\n *\n * A record entry is looked up one of two ways. When every value in it is its own number - as in every\n * entry a `{duals: 'number'}` read builds without `coerceNumericStrings` - a cell is still its own key,\n * and the entry only gives it a text: `textByNumber`. Any other entry can make a cell stand for another\n * key, or for more than one, and `byValue` lists every symbol holding each value, so all of them can be\n * weighed.\n *\n * @typedef {Object} ColumnSymbols\n * @property {string} name The field name.\n * @property {Array<number|string>} keys Each slot's number or string.\n * @property {Array<string|null>} texts Each slot's text, or null.\n * @property {Map<number|string, number>} byKey Key to slot.\n * @property {Map<number|string, number>} byCell Primitive cell to slot.\n * @property {Map<object, number>} byObject Dual object to slot, bounded.\n * @property {import('./util/storedSymbols.js').StoredSymbolsEntry|null} entry The field's record entry.\n * @property {Map<number|string, string>|null} textByNumber For an entry whose every value is its own\n * number, each number's first text.\n * @property {Map<number|string, number|Array<number>>|null} byValue For any other entry, each value's\n * index or indices in it.\n * @property {SlotFacts} facts What kinds of value the slots hold, for the header.\n */\n\n/**\n * What kinds of value a column's written symbols hold - what decides which of its tags and number\n * format still describe it.\n *\n * @typedef {Object} SlotFacts\n * @property {boolean} hasNumber Some symbol has a number: a pure number or a dual.\n * @property {boolean} hasNonNumber Some symbol is a pure string.\n * @property {boolean} hasFraction Some number is not a whole number.\n */\n\n/**\n * Whether every symbol in a record entry is keyed by the value its cell holds - the symbol's own number,\n * as it is for a dual read as its number and for a pure number recorded beside one.\n *\n * Such an entry cannot make a value ambiguous - each value stands for one number, and no symbol in it\n * is a string - and never maps a cell to a key other than itself. So the cell needs no map of its own\n * and no weighing of entries, only the text the first symbol holding it has.\n *\n * @param {import('./util/storedSymbols.js').StoredSymbolsEntry} entry The entry.\n * @return {boolean} True when every value is its symbol's number.\n */\nfunction valuesAreNumbers(entry) {\n const {values, numbers} = entry;\n\n // A pure string's number is null, which no value is the same as.\n for (let index = 0; index < values.length; index++) {\n if (!sameValueZero(values[index], numbers[index])) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * A slot added after the column's others, for a key it does not have. The caller puts the key in\n * `byKey`.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} key The number or string.\n * @param {string|null} text The text supplied with it, or null.\n * @return {number} The slot.\n */\nfunction newSlot(column, key, text) {\n const slot = column.keys.length;\n\n column.keys.push(key);\n column.texts.push(text);\n\n // Every slot is created here, so the facts cost nothing extra: no pass over the symbols afterwards.\n if (typeof key === 'number') {\n column.facts.hasNumber = true;\n if (!Number.isInteger(key)) column.facts.hasFraction = true;\n } else {\n column.facts.hasNonNumber = true;\n }\n\n return slot;\n}\n\n/**\n * The slot for a key, created at its first appearance.\n *\n * A text is attached to a number slot that has none, in place, whatever order the cells came in: a\n * plain number carries no text, so a dual with the same number supplies it rather than losing it. A\n * slot that already has a text keeps it, which is Qlik's rule - values sharing a number share the first\n * text encountered.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} key The number or string.\n * @param {string|null} text The text supplied with it, or null.\n * @return {number} The slot.\n */\nfunction slotFor(column, key, text) {\n let slot = column.byKey.get(key);\n\n if (slot === undefined) {\n slot = newSlot(column, key, text);\n column.byKey.set(key, slot);\n } else if (text !== null && column.texts[slot] === null && typeof key === 'number') {\n column.texts[slot] = text;\n }\n\n return slot;\n}\n\n/**\n * Whether some of a record entry's symbols say different things about the value they share: two\n * numbers, two texts of pure strings, or a number and a pure string. Those are the symbols one cell\n * could stand for, and the writer refuses to pick one.\n *\n * @param {ReadonlyArray<number>} indices Indices into the entry of symbols that read as one value.\n * @param {ReadonlyArray<number|null>} numbers The entry's numbers.\n * @param {ReadonlyArray<string|null>} texts The entry's texts.\n * @return {boolean} True when they stand for more than one stored value.\n */\nfunction standsForSeveral(indices, numbers, texts) {\n /** @type {number|null} */\n let number = null;\n /** @type {string|null} */\n let string = null;\n\n for (const index of indices) {\n if (numbers[index] !== null) {\n if (number === null) {\n number = numbers[index];\n } else if (!sameValueZero(number, numbers[index])) {\n return true;\n }\n } else if (string === null) {\n string = texts[index];\n } else if (string !== texts[index]) {\n return true;\n }\n }\n\n return number !== null && string !== null;\n}\n\n/**\n * Whether a field whose record entry this is could have been read with `{duals: 'text'}` and, read that\n * way without `coerceNumericStrings`, would still have a value that stands for more than one stored value.\n *\n * Without coercion such a read shows every symbol with a text as that text, and a pure number as itself,\n * so the entry's symbols are grouped that way and weighed as the writer weighs a cell. Every symbol that\n * could end up in such a group is in the entry already: a `'text'` read records every dual, and a string\n * with a dual's text is either numeric, so coercion read it as a number and recorded it, or not, so the\n * dual reads as that text with coercion too and the string is recorded beside it.\n *\n * A dual shown as its number whose text is not numeric proves the entry came from a `'number'` read,\n * because a `'text'` read shows that text. Without coercion a `'number'` read maps no value to two stored\n * values: every value it records is a number, and every symbol under one number has that number.\n *\n * @param {import('./util/storedSymbols.js').StoredSymbolsEntry} entry The entry.\n * @return {boolean} True when a `'text'` read without coercion could still be refused.\n */\nfunction ambiguousAsUncoercedText(entry) {\n const {values, numbers, texts} = entry;\n\n for (let index = 0; index < values.length; index++) {\n if (typeof values[index] === 'number' && numbers[index] !== null && texts[index] !== null) {\n // @ts-ignore - the text was just checked for null\n if (!isNumericText(texts[index])) {\n return false;\n }\n }\n }\n\n /** @type {Map<number|string|null, Array<number>>} */\n const byShown = new Map();\n\n for (let index = 0; index < values.length; index++) {\n const shown = texts[index] ?? numbers[index];\n const indices = byShown.get(shown);\n\n if (indices === undefined) {\n byShown.set(shown, [index]);\n } else {\n indices.push(index);\n }\n }\n\n for (const indices of byShown.values()) {\n if (indices.length > 1 && standsForSeveral(indices, numbers, texts)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether reading the field with `{duals: 'both'}`, coercion left as it was, would leave no value standing\n * for more than one stored value.\n *\n * `'both'` records no dual - each is a `QvdDual` cell of its own - so under a value such a read records the\n * entry's symbols less its duals: strings coercion read as that number, and pure symbols beside them. Every\n * one of those is in the entry already, whichever mode built it, because coercion and the pure symbols\n * beside what it records do not depend on the mode.\n *\n * @param {ColumnSymbols} column The column, whose entry has a value that stands for several stored values.\n * @return {boolean} True when `'both'` is enough.\n */\nfunction unambiguousWithoutDuals(column) {\n // @ts-ignore - only a column with a byValue map refuses a value, and it has an entry\n const {numbers, texts} = column.entry;\n\n // @ts-ignore - see above\n for (const found of column.byValue.values()) {\n if (typeof found !== 'number') {\n const kept = found.filter((/** @type {number} */ index) => numbers[index] === null || texts[index] === null);\n\n if (kept.length > 1 && standsForSeveral(kept, numbers, texts)) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * What to do about a field in which a value stands for more than one stored value - the end of that\n * refusal.\n *\n * It names the least change to the read after which no value of the field does, so it is worked out from\n * every value in the field's entry and not only the one refused: advice fitted to that one could lead to a\n * second refusal for another. The entry does not say which duals mode built it, only sometimes shows it: a\n * dual shown as its text comes from a `'text'` read, and one shown as its number whose text is not a\n * number from a `'number'` read. Where the least change depends on the mode, the sentence says how.\n *\n * - **No value stands for a string read as a number beside another stored value:** `{duals: 'both'}`, or\n * `QvdDual` cells. Coercion can stay on, because a string it reads as a number reads as that number in\n * every mode: had it made a value ambiguous, that value would be among the ones weighed.\n * - **One does, and dropping coercion is enough for any read:** without `coerceNumericStrings`. A string\n * then reads as itself, and under `'number'` and `'both'` nothing is left to record two stored values\n * under one value; see `ambiguousAsUncoercedText` for `'text'`.\n * - **Dropping coercion is not enough for a `'text'` read, and `{duals: 'both'}` is:** that, for any read.\n * A string `'4'` beside a dual 4 with the text `4` is the example: a `'text'` read without coercion shows\n * both as `'4'`, and `'both'` shows the dual as a `QvdDual`.\n * - **Neither is enough on its own for a `'text'` read:** both, when the entry shows a `'text'` read. When\n * it does not, the read may have been `'number'`, for which dropping coercion is enough, so the sentence\n * asks for `'both'` as well only if the field was read with `'text'`. Switching to `'number'` is not\n * enough either: it records every dual `'both'` leaves out, and what is ambiguous without them stays so.\n *\n * `'007'` and `'7'` read as 7 in every mode, so a refusal that named only `'both'` for them would send\n * the caller to a read that is refused again.\n *\n * @param {ColumnSymbols} column The column, whose entry has a value that stands for several stored values.\n * @return {string} The sentence.\n */\nfunction ambiguityRemedy(column) {\n // @ts-ignore - only a column with a byValue map refuses a value, and it has an entry\n const {values, numbers, texts} = column.entry;\n let coerced = false;\n let other = false;\n\n // @ts-ignore - see above\n for (const [value, found] of column.byValue) {\n if (typeof found !== 'number' && standsForSeveral(found, numbers, texts)) {\n // Under a value that is a number, every symbol with a number has that number, so what disagrees with\n // them is a pure string - and only coercion reads a pure string as a number.\n if (typeof value === 'number') {\n coerced = true;\n } else {\n other = true;\n }\n }\n }\n\n if (!coerced) {\n return \"Read the field with {duals: 'both'}, or write QvdDual cells.\";\n }\n\n // A value that is a string, and stands for several stored values, is a dual's text a 'text' read\n // showed, and dropping coercion leaves it as ambiguous as it was.\n // @ts-ignore - see above\n if (!other && !ambiguousAsUncoercedText(column.entry)) {\n return 'Read the field without {coerceNumericStrings: true}.';\n }\n\n if (unambiguousWithoutDuals(column)) {\n return \"Read the field with {duals: 'both'}.\";\n }\n\n // A dual shown as its text shows a 'text' read, and every value `other` counted is one.\n return values.some((value, index) => typeof value === 'string' && numbers[index] !== null)\n ? \"Read the field with {duals: 'both'} and without {coerceNumericStrings: true}.\"\n : \"Read the field without {coerceNumericStrings: true}, and with {duals: 'both'} as well if it was read \" +\n \"with {duals: 'text'}.\";\n}\n\n/**\n * The slot for a number or a string cell the column has not seen, through the frame's record.\n *\n * With no record entry for the value, the cell is its own key. Otherwise the entries holding it say\n * what it stands for: one pure string's text, or one number with the first text any of them has. When\n * they say more than one thing - two numbers, two texts, or a number and a string - the cell could be\n * either, and it is refused rather than written as one of them.\n *\n * The ambiguity is worked out here, from the entries themselves, rather than trusted to a read: a\n * record merged from two frames, or built by hand, is checked the same way. An entry whose every value\n * is its own number - see `valuesAreNumbers` - has no ambiguity to find, so the cell only takes its text.\n *\n * Called only for a cell the row loop has just looked for in `byCell` and not found, and whose slot the\n * row loop then puts there.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} value The cell.\n * @param {number} row The row, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {number} The slot.\n * @throws {QvdValidationError} If the record maps the value to more than one stored value.\n */\nfunction slotForCell(column, value, row, filePath) {\n // A cell that is its own key. `byCell` is `byKey` here, so the lookup that missed was for the key: the\n // slot is new, and the row loop's write of it is the write to `byKey`. Asking again, and writing twice,\n // cost two map operations per distinct value.\n if (column.byCell === column.byKey) {\n return newSlot(column, value, column.textByNumber === null ? null : (column.textByNumber.get(value) ?? null));\n }\n\n // @ts-ignore - a column whose cells have a map of their own has an entry that is not keyed by numbers\n const found = column.byValue.get(value);\n\n if (found === undefined) {\n return slotFor(column, value, null);\n }\n\n // @ts-ignore - byValue is only set together with entry\n const {numbers, texts} = column.entry;\n const indices = typeof found === 'number' ? [found] : found;\n\n if (standsForSeveral(indices, numbers, texts)) {\n /** @type {Array<{number: number|null, text: string|null}>} */\n const stored = [];\n\n for (const index of indices) {\n if (!stored.some((pair) => sameValueZero(pair.number, numbers[index]) && pair.text === texts[index])) {\n stored.push({number: numbers[index], text: texts[index]});\n }\n }\n\n throw new QvdValidationError(\n `The value ${JSON.stringify(value)} in field '${column.name}' (row ${row}) was read from ${stored.length} ` +\n `different stored values, so writing it back would have to guess which one. ${ambiguityRemedy(column)}`,\n {column: column.name, row, value, stored, file: filePath, stage: 'buildSymbolTable'},\n );\n }\n\n /** @type {number|null} */\n let number = null;\n /** @type {string|null} */\n let numberText = null;\n\n for (const index of indices) {\n // One stored value: a pure string here means every symbol holding the value is that string.\n if (numbers[index] === null) {\n // @ts-ignore - a symbol with no number has a text\n return slotFor(column, texts[index], null);\n }\n\n number ??= numbers[index];\n numberText ??= texts[index];\n }\n\n // @ts-ignore - every index came from an entry that holds a number or a text, and none was a string\n return slotFor(column, number, numberText);\n}\n\n/**\n * The slot for a dual object the column has not remembered.\n *\n * Keyed by its number, so a fresh object per row costs a validation and a lookup, and never a map\n * entry past the bound. Anything that is not a dual - see `asDual` - is refused.\n *\n * @param {ColumnSymbols} column The column.\n * @param {object} value The cell.\n * @param {number} row The row, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {number} The slot.\n * @throws {QvdValidationError} If the value is not a dual, or a half of it cannot be stored.\n */\nfunction slotForObject(column, value, row, filePath) {\n const dual = asDual(value);\n\n if (dual === null) {\n refuseCell(value, column.name, row, filePath);\n }\n\n const {number, text} = dual;\n\n // The problem functions allocate nothing for a good half, so the context is only built for a bad one.\n if (numberProblem(number) !== null) {\n checkNumber(number, 'The number of a dual value', {\n column: column.name,\n row,\n half: 'number',\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n if (textProblem(text) !== null) {\n checkText(text, 'The text of a dual value', {\n column: column.name,\n row,\n half: 'text',\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n const slot = slotFor(column, number, text);\n\n if (column.byObject.size < OBJECT_MEMO_BASE + 2 * column.keys.length) {\n column.byObject.set(value, slot);\n }\n\n return slot;\n}\n\n/** Tags that only hold while every value in the field has a number. */\nconst NUMERIC_TAGS = new Set(['$numeric', '$integer', '$date', '$time', '$timestamp']);\n\n/** Tags that only hold while every value in the field is plain text. */\nconst TEXT_TAGS = new Set(['$text', '$ascii']);\n\n/** Tags that only hold while every number in the field is a whole number. */\nconst WHOLE_NUMBER_TAGS = new Set(['$integer', '$date']);\n\n/** Number formats that describe how Qlik displays a number, and so mean nothing on a text field. */\nconst NUMERIC_FORMATS = new Set(['INTEGER', 'REAL', 'FIX', 'MONEY', 'DATE', 'TIME', 'TIMESTAMP', 'INTERVAL']);\n\n/** What a field with no number format of its own is written with. */\nconst UNKNOWN_NUMBER_FORMAT = Object.freeze({Type: 'UNKNOWN', nDec: '0', UseThou: '0', Fmt: '', Dec: '', Thou: ''});\n\n/**\n * The field's tags, less any the written values contradict.\n *\n * Tags are carried from the header a frame was read with, and a caller can change a field's values\n * without touching its tags - read a timestamp field with `{duals: 'text'}` and write it back, and the\n * values are text while the header still says `$numeric` and `$timestamp`, which tells Qlik a text\n * field is numeric. So a tag the values contradict is dropped:\n *\n * - a value with no number drops `$numeric`, `$integer`, `$date`, `$time` and `$timestamp`;\n * - a number that is not whole drops `$integer` and `$date`;\n * - any number drops `$text` and `$ascii`.\n *\n * The definitions are Qlik's field-tag help: `$numeric` - every non-NULL value is numeric; `$integer`\n * - every value is an integer; `$date` - every value can be read as a date, which it defines as an\n * integer; `$text` - no value is numeric. The bundled Qlik files agree where they can: `$text` and\n * `$ascii` appear only on fields whose every value is a pure string, and a field mixing strings and\n * numbers carries neither. They also show what not to derive. Qlik keeps `$ascii` on fields holding\n * characters outside ASCII - their first such value is always past the hundredth symbol, so it looks\n * like a judgement from the first values rather than all of them - and keeps `$timestamp` on a field of\n * timestamps some of which fall exactly on midnight, so a whole number does not contradict it. The\n * reference files in `docs/reference-qvds/` carry `$date`, and only on fields whose every number is\n * whole, which is what the `$date` rule assumes. No file carries `$time`, not even a field Qlik built\n * with `Time()`, so that rule still rests on the help alone.\n *\n * Only removes, never adds. A tag Qlik would have added is Qlik's to add on its next load; inventing\n * one here would be the writer asserting something it has no way to know - `$date` over an integer\n * field, say. `$key`, `$hidden` and custom tags pass through.\n *\n * @param {any} tags The field's tags as carried in the metadata: `{String: string | string[]}`, or\n * something else, which is returned untouched.\n * @param {SlotFacts|undefined} facts What the field's written symbols hold.\n * @return {any} The tags to write.\n */\nfunction pruneContradictedTags(tags, facts) {\n if (tags === null || typeof tags !== 'object' || tags.String === undefined || facts === undefined) {\n return tags || {};\n }\n\n const list = Array.isArray(tags.String) ? tags.String : [tags.String];\n const kept = list.filter((/** @type {string} */ tag) => {\n if (facts.hasNonNumber && NUMERIC_TAGS.has(tag)) return false;\n if (facts.hasFraction && WHOLE_NUMBER_TAGS.has(tag)) return false;\n if (facts.hasNumber && TEXT_TAGS.has(tag)) return false;\n return true;\n });\n\n if (kept.length === list.length) {\n return tags;\n }\n\n return kept.length === 0 ? {} : {...tags, String: kept};\n}\n\n/**\n * The field's number format, reset when the field no longer holds a number to apply it to.\n *\n * A `DATE` or `MONEY` format on a field whose values are all text describes nothing, and misleads\n * whoever reads the header next. A field that still has a single number keeps its format: Qlik's own\n * files carry `REAL` on a field holding only the integer 0 and `MONEY` on fields where some amounts are integers,\n * so no other mismatch is a contradiction.\n *\n * @param {any} numberFormat The field's number format as carried in the metadata.\n * @param {SlotFacts|undefined} facts What the field's written symbols hold.\n * @return {any} The number format to write.\n */\nfunction resetContradictedNumberFormat(numberFormat, facts) {\n if (!numberFormat) {\n return {...UNKNOWN_NUMBER_FORMAT};\n }\n\n if (facts !== undefined && !facts.hasNumber && facts.hasNonNumber && NUMERIC_FORMATS.has(numberFormat.Type)) {\n return {...UNKNOWN_NUMBER_FORMAT};\n }\n\n return numberFormat;\n}\n\n/**\n * Maximum length of a single fs.write call. Node checks that a write's length fits in an Int32 and\n * rejects one of 2 GiB or more with a RangeError, so a symbol or index table that large could not be\n * written in one call at all. QvdFileReader caps its reads at the same size, and there an oversized\n * length aborts the process rather than throwing.\n */\nconst WRITE_CHUNK_SIZE = 512 * 1024 * 1024;\n\nexport class QvdFileWriter {\n /**\n * Constructs a new QVD file writer.\n *\n * @param {string} filePath The path to the QVD file to write.\n * @param {QvdDataFrame} df The data frame to write to the QVD file.\n * @param {Object} [options={}] Options for the writer.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function.\n * @param {boolean} [options.atomic=true] Whether to replace the destination rather than rewrite it:\n * the file is built beside it under a temporary name and renamed over it, so a failure leaves the\n * previous file exactly as it was and nothing ever reads a part-written one. False rewrites the\n * destination in place, which is what every version before 2.0.0 did: that keeps the file's\n * identity - hard links, its owner, permissions set on the file itself - needs no room for two\n * copies at once and no permission to create files in the directory, and destroys the previous\n * file the moment the write begins. A file that does not exist yet is renamed into place either\n * way, since there is nothing to rewrite - see `_destination`.\n * @param {boolean} [options.fsync=true] Whether to wait for the file's contents to reach the disk\n * before the write is finished. It is what carries an atomic write's promise through a power\n * loss - the contents are on the disk before anything is renamed, so a crash leaves the previous\n * file or the new one and never a damaged one - and it is the only thing that reports a failing\n * disk's deferred error rather than losing it. The rename itself is not flushed, so a crash just\n * after the call can still lose the replacement, or a file that did not exist before. False\n * resolves as soon as the operating system has accepted the bytes, which is faster and is what\n * every version before 2.0.0 did.\n */\n constructor(filePath, df, options = {}) {\n const {allowedDir, onProgress, atomic, fsync} = options;\n const checked = checkPath(filePath, allowedDir);\n this._path = checked.path;\n /**\n * The allowed directory, resolved. Kept because the path is checked again immediately before the\n * file is written - see `_destination` - and building the tables first can take seconds, which is\n * a long time for a path to go unwatched. That check is made against the directory this one was.\n */\n this._allowedDir = checked.base;\n // Unset means on for both: a null out of optional configuration or a JSON round trip must not\n // quietly become the way that loses the previous file. `booleanOption` says the rest.\n this._atomic = booleanOption(atomic, {option: 'atomic', file: this._path, whenUnset: true});\n this._fsync = booleanOption(fsync, {option: 'fsync', file: this._path, whenUnset: true});\n this._df = df;\n this._onProgress = onProgress;\n this._header = null;\n this._symbolBuffer = null;\n /**\n * Symbols written per column. It used to be the symbols themselves, as QvdSymbol objects, kept\n * alive through the header build and the file write for the sake of their count.\n *\n * @type {Array<number>|null}\n */\n this._symbolCounts = null;\n /** @type {Array<SlotFacts>|null} What each column's symbols hold, for pruning its tags. */\n this._symbolFacts = null;\n /** @type {Array<any>|null} */\n this._symbolTableMetadata = null;\n this._indexBuffer = null;\n /**\n * How each column's cells find their stored index: the slot maps `_buildSymbolTable` built.\n *\n * Built while the symbol table is, because that pass already decides the order symbols are\n * written in and therefore what each index is. The alternative - re-deriving it here from\n * a QvdSymbol and a template-literal key per cell - meant converting every cell twice and\n * allocating 34 million strings on the taxi fixture to look up something already known.\n *\n * With them, how many distinct numbers each column's cell map holds and how many of its cells are plain\n * numbers, which the index table pass's tables are sized and judged by: exact wherever the count could\n * decide whether a column gets a table, and otherwise the most there could be.\n *\n * @type {Array<{byCell: Map<number|string, number>, byKey: Map<number|string, number>,\n * byObject: Map<object, number>, numbers: number, cells: number}>|null}\n */\n this._symbolIndexByValue = null;\n /** @type {Array<any>|null} */\n this._indexTableMetadata = null;\n /** Rows written, kept because the index table is no longer an array to count. @type {number} */\n this._recordCount = 0;\n this._recordByteSize = null;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * @param {string} stage The current stage of the operation.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n this._onProgress({\n stage,\n current,\n total,\n percent,\n });\n }\n }\n\n /**\n * Writes the data to the QVD file.\n */\n async _writeData() {\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolBuffer, 'The QVD file symbol table has not been parsed.');\n assert(this._indexBuffer, 'The QVD file index table has not been parsed.');\n\n this._emitProgress('write', 0, 1);\n\n // @ts-ignore - Buffer.concat type compatibility\n const headerBuffer = Buffer.concat([Buffer.from(this._header, 'utf-8'), Buffer.from([0])]);\n\n // Every file-system call below goes through this, so a missing directory, a permission error or\n // a write the disk refuses is a QvdIOError carrying the system code rather than Node's bare error.\n // The close included: a network share can report a write's failure only when the file is closed.\n // `context.file` is the path the caller named even where the call that failed was made on the\n // temporary file, which is the file they asked to write; Node's own message, kept whole, names it.\n const failed = rethrowAsIoError(this._path, 'write');\n const destination = this._destination();\n\n if (destination.replace) {\n await this._replaceFile(destination, headerBuffer, failed);\n } else {\n await this._writeInPlace(destination, headerBuffer, failed);\n }\n\n // Reported once the file is in place rather than once the last byte has been accepted, so a write\n // that then fails to be flushed, closed or renamed has not already said it finished.\n this._emitProgress('write', 1, 1);\n }\n\n /**\n * What is at the destination, and therefore how it is to be written.\n *\n * Decided by one containment check, made now - immediately before anything is opened - and by\n * nothing else: the file that check approved is the file written, in either mode, and what the\n * check found there is what decides how.\n *\n * It used to stat and resolve the path again for itself, after the check. That second resolution\n * was #247 in the atomic write: a destination swapped for a symlink after the check was followed by\n * it, so the temporary file was built beside a file outside allowedDir and renamed over it. A check\n * reports where it went, so nothing here has to go there again.\n *\n * @return {{checked: import('./util/validatePath.js').CheckedPath, path: string,\n * existing: import('fs').BigIntStats|null, replace: boolean, sync: boolean}} The check, the file it\n * approved, what was there, whether to replace it rather than rewrite it, and whether to flush it.\n * @private\n */\n _destination() {\n // The file an open of the path reaches - its canonical path, so a symlink at the destination is\n // followed and kept, the file at its end replaced; or, where nothing exists yet, the name at the far\n // end of any dangling links, which is where an open() of the path would create it. Both write\n // modes use this one answer, so they agree about which file a symlink names.\n const checked = checkPath(this._path, this._allowedDir);\n const existing = checked.stats;\n\n // A destination that exists and is not a regular file is written in place whatever was asked for,\n // and never flushed. Replacing a device or a FIFO would replace the device: a root process writing\n // to /dev/null would leave a QVD where /dev/null was. A directory is refused rather than written:\n // by the open on POSIX, and on Windows - which opens a directory for writing when it is not also\n // asked to empty it - by the first write, before any byte lands. And fsync on something that is not\n // a file is EINVAL, which would fail a write that is otherwise fine.\n const special = existing !== null && !existing.isFile();\n\n // A name nothing is at yet is written by building the file beside it and renaming it there, in\n // either mode. There is nothing to rewrite, so the file that results is the one an in-place write\n // would have made - and a rename replaces the name rather than following anything at it, which an\n // open that creates cannot promise: on Windows even O_EXCL follows a dangling symlink planted at\n // the name, and creates the file wherever it points. So the in-place write is only ever a rewrite\n // of a file that exists, and `openChecked` is only asked to rewrite one it can hold to an identity.\n const replace = (this._atomic || existing === null) && !special;\n\n return {\n checked,\n path: checked.target,\n existing,\n replace,\n sync: this._fsync && !special,\n };\n }\n\n /**\n * Rewrites the destination where it stands - the way every version before 2.0.0 wrote.\n *\n * The file is emptied as the write begins, so from there until the last byte is written there is no\n * previous version left: a failure part-way through leaves a stub that no read of its rows survives,\n * and anything reading the path meanwhile sees however much of the new file has arrived.\n *\n * It is emptied by `openChecked` rather than by opening with `'w'`, and later than `'w'` would: once\n * the descriptor is known to be the file the check approved. `'w'` empties whatever the open reaches,\n * which is what let #247 truncate a file outside allowedDir through a symlink swapped in after the\n * check. The file that results is the same.\n *\n * @param {{checked: import('./util/validatePath.js').CheckedPath, sync: boolean}} destination Where\n * to write, from `_destination`.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _writeInPlace(destination, headerBuffer, failed) {\n // Closed by `closeAfter` rather than in a `finally`, so a close that fails after a write already\n // has cannot replace the write's error - the ENOSPC that explains the failure, not the close's EIO.\n const fd = await openChecked(destination.checked, 'rewrite', failed);\n\n await closeAfter(fd, failed, async () => {\n await this._writeParts(fd, headerBuffer, failed);\n\n if (destination.sync) {\n await fd.sync().catch(failed);\n }\n });\n }\n\n /**\n * Builds the file beside the destination and renames it over it.\n *\n * Nothing touches the destination until the rename, which either replaces it or leaves it as it was,\n * so a write that fails at any step - a full disk, a process killed, an error from the disk itself -\n * costs the temporary file and nothing else. A reader of the path gets the previous file or the new\n * one, never a part of either, which is the other half of what the old behaviour could not promise.\n *\n * @param {{path: string, existing: import('fs').BigIntStats|null, sync: boolean}} destination Where to\n * write, from `_destination`.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _replaceFile(destination, headerBuffer, failed) {\n const temporary = temporaryPathFor(destination.path);\n // 'wx' rather than 'w', so a name that somehow exists already is never written through. A\n // temporary standing in for a file that exists is created private and given that file's\n // permissions once it is whole: Node creates a file 0666 less the umask, which on a usual machine\n // would leave a half-written copy of a 0600 QVD readable by everyone until the chmod below, and\n // longer if its removal fails. A destination that does not exist yet gets the ordinary mode, which\n // is what a write of a new file has always produced.\n const mode = destination.existing === null ? undefined : 0o600;\n const fd = await fs.promises.open(temporary, 'wx', mode).catch(failed);\n\n try {\n await closeAfter(fd, failed, async () => {\n await this._writeParts(fd, headerBuffer, failed);\n\n // The file that appears keeps the permissions of the one it replaces. Through the handle\n // rather than as the open's mode, which the process umask masks. Not on Windows, where the\n // mode is the read-only attribute and nothing else: copying that would leave a temporary file\n // Windows then refuses to rename or to remove.\n if (destination.existing !== null && process.platform !== 'win32') {\n // The check's stats are BigInts - identity needs every bit of a Windows file ID - so the mode\n // is converted before it is masked: a BigInt and a Number do not mix in `&`.\n await fd.chmod(Number(destination.existing.mode) & 0o777).catch(failed);\n }\n\n // Before the rename, not after it, so that what a crash can lose is the replacement and never\n // the contents: the destination is the old file or the new one, whenever the power goes.\n if (destination.sync) {\n await fd.sync().catch(failed);\n }\n });\n\n await renameOver(temporary, destination.path).catch(failed);\n } catch (error) {\n // The destination has not been touched, so the temporary file is all this attempt leaves.\n const removed = await removeTemporary(temporary);\n\n // The removal can be refused too - on Windows while something else still holds the file open.\n // The error on its way out is the one that explains the write, so it is not replaced; the file\n // left behind is named in its context instead, which is the only way a caller could learn of it.\n //\n // Only where that context will take it. A module is strict code, so assigning to a frozen or\n // sealed object throws, and an error about the tidying up would then replace the ENOSPC that\n // explains the write - which is the whole point of `closeAfter`, undone at the last step. No\n // error reaching here carries a frozen context today; this is so that none ever can.\n const context = /** @type {{context?: Record<string, unknown>}} */ (error)?.context;\n if (!removed && context !== null && typeof context === 'object' && Object.isExtensible(context)) {\n context.temporaryFile = temporary;\n }\n\n throw error;\n }\n }\n\n /**\n * Writes the three parts of a QVD, in their order, into an open file.\n *\n * @param {import('fs/promises').FileHandle} fd The open file.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _writeParts(fd, headerBuffer, failed) {\n await this._writeRange(fd, headerBuffer, 0, failed);\n await this._writeRange(fd, this._symbolBuffer, headerBuffer.length, failed);\n await this._writeRange(fd, this._indexBuffer, headerBuffer.length + this._symbolBuffer.length, failed);\n }\n\n /**\n * Writes the whole of one buffer into the file, starting at `filePosition`.\n *\n * A write can resolve having written less than it was given, and that is all a disk that fills\n * part-way through one says. libuv retries a short write(2) itself, and when the retry fails it\n * returns the bytes that did land instead of the error - `uv__fs_write_all` in its `src/unix/fs.c`,\n * and `fs__write` on Windows does the same - so Node resolves with a short `bytesWritten` and never\n * rejects. Taking that for the whole write is how `toQvd()` resolved on a full disk and left a\n * truncated file: the index table, the last of the three writes, stopped part-way, and no later call\n * asked the disk again.\n *\n * So the rest is written until there is none, and it is the next call that reports the failure: the\n * disk refuses it outright, and that rejection is a QvdIOError with the system's code, ENOSPC, like\n * any other refused write. A write that stores nothing and reports nothing would repeat forever, so\n * it is a failure too, the one QvdIOError with no system code to carry.\n *\n * In bounded chunks as well, because Node refuses a single write of 2 GiB or more.\n *\n * @param {import('fs/promises').FileHandle} fd The open file.\n * @param {Buffer} buffer What to write.\n * @param {number} filePosition Where in the file it starts.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler, which every call\n * goes through.\n * @private\n */\n async _writeRange(fd, buffer, filePosition, failed) {\n let done = 0;\n\n while (done < buffer.length) {\n const length = Math.min(WRITE_CHUNK_SIZE, buffer.length - done);\n const {bytesWritten} = await fd.write(buffer, done, length, filePosition + done).catch(failed);\n\n // Not `=== 0`: a count that is not a positive number - from a patched `fs`, say - would make\n // `done` NaN and end the loop as though the part were written, which is this bug over again.\n if (!(bytesWritten > 0)) {\n throw new QvdIOError(\n `Could not write the QVD file: nothing was written at byte ${filePosition + done}, ` +\n 'and the operating system reported no error.',\n {file: this._path, operation: 'write', filePosition: filePosition + done},\n );\n }\n\n done += bytesWritten;\n }\n }\n\n /**\n * Builds the XML header of the QVD file.\n */\n _buildHeader() {\n this._emitProgress('header', 0, 1);\n const creationDate = new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '');\n /** @type {import('./QvdDataFrame.js').QvdMetadata|null} */\n const existingMetadata = this._df.metadata;\n\n // Use existing metadata if available, otherwise create default values\n const baseMetadata = existingMetadata\n ? {\n QvBuildNo: existingMetadata.QvBuildNo || 50667,\n CreatorDoc: existingMetadata.CreatorDoc || crypto.randomUUID(),\n CreateUtcTime: existingMetadata.CreateUtcTime || creationDate,\n SourceCreateUtcTime: existingMetadata.SourceCreateUtcTime || '',\n SourceFileUtcTime: existingMetadata.SourceFileUtcTime || '',\n SourceFileSize: existingMetadata.SourceFileSize || -1,\n StaleUtcTime: existingMetadata.StaleUtcTime || '',\n TableName: existingMetadata.TableName || path.basename(this._path, path.extname(this._path)),\n Compression: existingMetadata.Compression || '',\n Comment: existingMetadata.Comment || '',\n EncryptionInfo: existingMetadata.EncryptionInfo || '',\n TableTags: existingMetadata.TableTags || '',\n ProfilingData: existingMetadata.ProfilingData || '',\n Lineage: existingMetadata.Lineage || {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n }\n : {\n QvBuildNo: 50667,\n CreatorDoc: crypto.randomUUID(),\n CreateUtcTime: creationDate,\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: path.basename(this._path, path.extname(this._path)),\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n };\n\n // Get existing field metadata if available\n /** @type {any[]} */\n let existingFields = [];\n if (existingMetadata && existingMetadata.Fields && existingMetadata.Fields.QvdFieldHeader) {\n existingFields = Array.isArray(existingMetadata.Fields.QvdFieldHeader)\n ? existingMetadata.Fields.QvdFieldHeader\n : [existingMetadata.Fields.QvdFieldHeader];\n }\n\n const xmlObject = {\n QvdTableHeader: {\n ...baseMetadata,\n Fields: {\n QvdFieldHeader: this._df.columns.map((/** @type {any} */ column, /** @type {number} */ index) => {\n // Find existing field metadata for this column\n const existingField = existingFields.find((/** @type {any} */ f) => f.FieldName === column);\n\n return {\n FieldName: column,\n BitOffset: this._indexTableMetadata?.[index][0],\n BitWidth: this._indexTableMetadata?.[index][1],\n Bias: this._indexTableMetadata?.[index][2],\n NoOfSymbols: this._symbolCounts?.[index],\n Offset: this._symbolTableMetadata?.[index][0],\n Length: this._symbolTableMetadata?.[index][1],\n Comment: existingField?.Comment || '',\n NumberFormat: resetContradictedNumberFormat(existingField?.NumberFormat, this._symbolFacts?.[index]),\n Tags: pruneContradictedTags(existingField?.Tags, this._symbolFacts?.[index]),\n };\n }),\n },\n NoOfRecords: this._recordCount,\n RecordByteSize: this._recordByteSize,\n Offset:\n this._symbolTableMetadata && this._symbolTableMetadata.length > 0\n ? this._symbolTableMetadata[this._symbolTableMetadata.length - 1][0] +\n this._symbolTableMetadata[this._symbolTableMetadata.length - 1][1]\n : 0,\n Length: this._indexBuffer?.length,\n },\n };\n\n // Every text the builder is about to write, so a character XML cannot hold is refused naming the\n // property it is in. The field names were checked before the rows were.\n const {Fields, ...table} = xmlObject.QvdTableHeader;\n\n for (const [property, value] of Object.entries(table)) {\n checkHeaderTexts(value, property, 'the table', {file: this._path, stage: 'buildHeader'});\n }\n\n for (const {FieldName, ...field} of Fields.QvdFieldHeader) {\n for (const [property, value] of Object.entries(field)) {\n checkHeaderTexts(value, property, `field '${FieldName}'`, {\n column: FieldName,\n file: this._path,\n stage: 'buildHeader',\n });\n }\n }\n\n const builder = new xml.Builder({\n renderOpts: {\n pretty: true,\n newline: '\\r\\n',\n indent: ' ',\n },\n });\n this._header = builder.buildObject(xmlObject) + '\\r\\n';\n this._emitProgress('header', 1, 1);\n }\n\n /**\n * Builds the symbol table of the QVD file.\n *\n * One pass over the rows finds each column's distinct values in the order they first appear,\n * which is the order Qlik lists symbols in, and checks each distinct value once. A second pass per\n * column encodes them: every symbol is sized first, then written into one buffer of exactly that\n * size.\n *\n * What each value is stored as:\n *\n * | Cell | Symbol |\n * | --- | --- |\n * | `null`, `undefined`, a hole, a missing cell | none - the field's `Bias` records NULL |\n * | an integer from -2147483648 to 2147483647, -0 included | pure int, type 1 |\n * | any other finite number | pure double, type 2 |\n * | a string | pure string, type 4 |\n * | a dual - a `QvdDual`, or an object whose only keys are `number` and `text` | dual int or dual double, type 5 or 6, by the number |\n * | a number or a string the frame's `storedSymbols` records | the symbol it was read from |\n *\n * A number is a pure number, with no text. It used to be written as a dual whose text was\n * `String(value)`, which was wrong twice over: it invented text the caller never supplied, and a\n * file Qlik wrote with pure numbers came back out of a read and a write with every one of them\n * turned into a dual. The kind follows `isStoredAsInt`, which is the rule Qlik's own files follow.\n * A string is never parsed, so `'7'` and `7` in one column are two symbols. It is stored as its\n * UTF-8 bytes, or refused where those bytes would not give it back: a NUL ends a stored text, and\n * an unpaired surrogate has no UTF-8 encoding at all.\n *\n * A column holds one symbol per number, as a Qlik field does. Several duals with one number are one\n * symbol with the first text in row order, and a plain number with the same number as a dual joins\n * the dual, in either order - so no text a caller supplied is lost to a plain number that came\n * first. A string is not a number, so a string equal to a dual's text is a symbol of its own.\n *\n * A frame read from a file shows one half of some symbols: a dual read as its number or its text, a\n * string read as a number. Its record says what each such cell stands for, so the frame writes back\n * the symbols it was read from - the dual's text, Qlik's exact double, the string `'007'` - whichever\n * rows the cells were moved to. A cell the record maps to more than one stored value is refused.\n *\n * The complexity claim is the one to trust here: O(rows x columns) for the pass, and O(symbols)\n * for the encoding. The \"80-90% improvement\" this comment once carried is not reproducible in this\n * repository; `benchmarks/` measures what the writer costs now, which is the useful number.\n *\n * @private\n */\n _buildSymbolTable() {\n this._symbolCounts = [];\n this._symbolFacts = [];\n this._symbolTableMetadata = [];\n this._symbolIndexByValue = [];\n\n // A table with no fields is not a QVD. Writing one produced a 741-byte file with an empty\n // `<Fields/>` element that this same library refuses to load, which is the worst of both:\n // the write reports success and the failure surfaces later, somewhere else.\n if (this._df.columns.length === 0) {\n throw new QvdValidationError('A QVD file must have at least one field', {\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numColumns = columns.length;\n const numRows = data.length;\n\n validateColumnNames(columns, this._path);\n\n // Through the same check a frame's constructor applies, which costs nothing for a record that came\n // from a read or was already checked, and refuses a malformed one handed to the writer directly.\n const record = normaliseStoredSymbols(this._df.storedSymbols);\n\n this._emitProgress('symbol-table', 0, numColumns);\n\n // Per column, the slots in first-appearance order and the maps that find them - see\n // ColumnSymbols. A Map compares keys by SameValueZero, so a number is one symbol however many rows\n // hold it, and 0 and -0 in one column are one symbol - which isStoredAsInt stores as the integer 0\n // either way.\n //\n // No third structure: this used to be a Set per column, then `Array.from` on it, then a Map built\n // from the array, three structures each holding a reference to every distinct value. On a column\n // whose values are all distinct that was roughly 30MB of duplication per million rows.\n /** @type {Array<ColumnSymbols>} */\n const state = columns.map((/** @type {string} */ name) => {\n const entry = record === null ? null : (record.find((candidate) => candidate.field === name) ?? null);\n /** @type {Map<number|string, number>} */\n const byKey = new Map();\n /** @type {Map<number|string, number|Array<number>>|null} */\n let byValue = null;\n /** @type {Map<number|string, string>|null} */\n let textByNumber = null;\n\n if (entry !== null && valuesAreNumbers(entry)) {\n textByNumber = firstTextByValue(entry);\n } else if (entry !== null) {\n byValue = new Map();\n\n // An index per value, and an array only for a value two entries share, which a record read from\n // a Qlik file never has: a field of distinct duals costs a map entry per value, not an array.\n for (let index = 0; index < entry.values.length; index++) {\n const found = byValue.get(entry.values[index]);\n\n if (found === undefined) {\n byValue.set(entry.values[index], index);\n } else if (typeof found === 'number') {\n byValue.set(entry.values[index], [found, index]);\n } else {\n found.push(index);\n }\n }\n }\n\n return {\n name,\n keys: [],\n texts: [],\n byKey,\n // A cell is its own key without a record entry, and with one whose values are their numbers, so\n // one Map serves both. On a field of distinct duals that is a map entry per symbol fewer.\n byCell: entry === null || textByNumber !== null ? byKey : new Map(),\n byObject: new Map(),\n entry,\n textByNumber,\n byValue,\n facts: {hasNumber: false, hasNonNumber: false, hasFraction: false},\n };\n });\n\n // Hoisted out of the column objects, so the row loop's common case - a primitive the column has seen -\n // costs array reads and one Map lookup, or none for a number its table holds. A dual object has lookups\n // of its own.\n const byCells = state.map((column) => column.byCell);\n const byObjects = state.map((column) => column.byObject);\n /** @type {Array<boolean>} */\n const containsNull = columns.map(() => false);\n // In front of each column's cell map, from its first plain number, the numbers the column has just looked\n // up in it. Why a number found there can be taken as present unasked, and when a table is switched off -\n // null from then on - is src/util/seenNumbers.js's opening comment.\n const pool = new SlotPool();\n /** @type {Array<import('./util/seenNumbers.js').SeenNumbers|null>} */\n const seen = columns.map(() => NO_TABLE_YET);\n const firstJudgement = firstJudgementRow(numRows);\n // For the index table pass, which judges a table against how many of its column's cells are numbers: a\n // table counts them while it is on, and where it stopped - the row, and its count until then - is kept so\n // that the rest can be counted after this pass rather than on every cell.\n /** @type {Array<{row: number, cells: number}|null>} */\n const stopped = columns.map(() => null);\n\n // A counted loop, not `data.forEach`. forEach skips array holes and the index table's loop\n // does not, so a sparse `data` array made the two passes disagree about how many rows\n // exist: a five-element array with one row set wrote a five-row file in which four rows\n // carried a real value copied from the fifth, and a hole between two rows threw a bare\n // TypeError. A hole reads as `undefined`, which is what this writer already treats as NULL\n // everywhere else, so both passes now see the same rows and a hole becomes a NULL row.\n for (let row = 0; row < numRows; row++) {\n if ((row % WINDOW_ROWS === 0 && row !== 0) || row === firstJudgement) {\n endWindow(seen, row, stopped);\n }\n\n const values = data[row];\n\n // A missing row is a row of NULLs, which is what a hole in a sparse array already means.\n // A row that is present but is not an array is different: `values?.[column]` reads\n // `undefined` from it for every column, so `{columns: ['a'], data: [1, 2]}` used to write a\n // two-row file of NULLs and report success, discarding everything the caller passed.\n if (values !== null && values !== undefined && !Array.isArray(values)) {\n throw new QvdValidationError('Each row must be an array of values', {\n row,\n type: typeof values,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n // A short row is padded with NULLs, deliberately. A long one is not truncated, because\n // dropping the extra cells silently is how a caller whose columns and data have drifted\n // apart gets a plausible file with a column missing.\n if (values !== null && values !== undefined && values.length > numColumns) {\n throw new QvdValidationError(`Row ${row} has ${values.length} values but there are ${numColumns} fields`, {\n row,\n values: values.length,\n fields: numColumns,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n containsNull[column] = true;\n continue;\n }\n\n // A dual object is looked up by identity in its own map, so the primitive map is never asked\n // about an object it cannot hold.\n if (typeof value === 'object') {\n if (!byObjects[column].has(value)) {\n slotForObject(state[column], value, row, this._path);\n }\n\n continue;\n }\n\n // A number the column has just looked up is found in its table, and the map is not asked.\n let table = null;\n let slot = 0;\n\n if (typeof value === 'number') {\n table = seen[column];\n\n if (table !== null) {\n table.cells++;\n slot = slotOf(value, table.mask);\n\n if (table.values[slot] === value) {\n continue;\n }\n\n table.misses++;\n\n // The column's first plain number, which it gets its own table for, counting this lookup as a miss.\n if (table === NO_TABLE_YET) {\n table = symbolPassTable(numRows, pool);\n seen[column] = table;\n\n if (table === null) {\n stopped[column] = {row, cells: 0};\n } else {\n table.cells = 1;\n table.misses = 1;\n slot = slotOf(value, table.mask);\n }\n }\n }\n }\n\n // Any other primitive the column has already seen costs this one lookup, as it did before duals.\n if (byCells[column].has(value)) {\n if (table !== null) {\n table.values[slot] = value;\n }\n\n continue;\n }\n\n // Once per distinct value, not once per row: a repeat has already been through this. The\n // problem functions allocate nothing for a good value, so the context object is only built\n // for a value that is about to be refused.\n if (typeof value === 'number') {\n if (numberProblem(value) !== null) {\n checkNumber(value, null, {column: columns[column], row, file: this._path, stage: 'buildSymbolTable'});\n }\n } else if (typeof value === 'string') {\n if (textProblem(value) !== null) {\n checkText(value, 'A string value', {\n column: columns[column],\n row,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n } else {\n refuseCell(value, columns[column], row, this._path);\n }\n\n byCells[column].set(value, slotForCell(state[column], value, row, this._path));\n\n // After the map has it, so that a slot never holds a number the map does not.\n if (table !== null && typeof value === 'number') {\n seen[column] = table.remember(slot, value);\n }\n }\n }\n\n // Serialised per column and concatenated once. Concatenating onto an accumulating buffer\n // instead re-copies every byte written so far on each column - O(bytes x columns), which\n // measured 26ms against 14ms on a 67MB symbol table and gets worse linearly with the column\n // count, while transiently holding two copies of everything written so far.\n /** @type {Array<Buffer>} */\n const columnBuffers = [];\n let symbolsOffset = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const {keys, texts} = state[column];\n const kinds = new Uint8Array(keys.length);\n let byteLength = 0;\n // The number keys, counted here because this loop visits every slot anyway: where the cells are found\n // in the key map, they are the distinct numbers the index table pass will meet.\n let numberKeys = 0;\n\n for (let slot = 0; slot < keys.length; slot++) {\n const key = keys[slot];\n const text = texts[slot];\n\n if (typeof key === 'number') {\n numberKeys++;\n\n // Both halves were checked when the cell was, or when the record was; this is the last look\n // before the bytes are written. A record a read built is taken as the file stored it, so a\n // damaged file's NaN dual read as its text reaches a slot only through the record - and is\n // refused here as the NaN cell it stands for would have been.\n if (numberProblem(key) !== null) {\n checkNumber(key, null, {column: columns[column], file: this._path, stage: 'buildSymbolTable'});\n }\n\n if (text !== null && textProblem(text) !== null) {\n checkText(text, 'The text of a dual value', {\n column: columns[column],\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n kinds[slot] = kindOf(key, text);\n byteLength += symbolByteLength(kinds[slot], key, text);\n } else {\n kinds[slot] = kindOf(null, key);\n byteLength += symbolByteLength(kinds[slot], null, key);\n }\n }\n\n // allocUnsafe, because every byte is about to be written. The assertion below holds it to that:\n // a byte left unwritten would carry whatever memory the buffer was given into the file.\n const columnBuffer = Buffer.allocUnsafe(byteLength);\n let offset = 0;\n\n for (let slot = 0; slot < keys.length; slot++) {\n const key = keys[slot];\n\n offset =\n typeof key === 'number'\n ? writeSymbol(columnBuffer, offset, kinds[slot], key, texts[slot])\n : writeSymbol(columnBuffer, offset, kinds[slot], null, key);\n }\n\n assert(offset === byteLength, 'A column was encoded into a different number of bytes than it was sized for.');\n\n columnBuffers.push(columnBuffer);\n this._symbolTableMetadata?.push([symbolsOffset, byteLength, containsNull[column]]);\n this._symbolCounts?.push(keys.length);\n this._symbolFacts?.push(state[column].facts);\n const numbers = state[column].byCell === state[column].byKey ? numberKeys : numbersIn(state[column].byCell);\n const table = seen[column];\n\n this._symbolIndexByValue?.push({\n byCell: state[column].byCell,\n byKey: state[column].byKey,\n byObject: state[column].byObject,\n numbers,\n cells:\n table === NO_TABLE_YET\n ? 0\n : table !== null\n ? table.cells\n : numericCellsAfter(data, column, /** @type {{row: number, cells: number}} */ (stopped[column]), numbers),\n });\n\n symbolsOffset += byteLength;\n\n this._emitProgress('symbol-table', column + 1, numColumns);\n }\n\n // @ts-ignore - Buffer.concat type compatibility\n this._symbolBuffer = Buffer.concat(columnBuffers);\n }\n\n /**\n * Builds the bit-packed index table of the QVD file.\n *\n * A record is `recordByteSize` bytes. Each column occupies `bitWidth` consecutive bits at\n * `bitOffset`, least significant bit first, where bit `p` of a record is\n * `(byte[p >> 3] >> (p & 7)) & 1`. `Bias` is -2 for a column containing NULLs: stored index 0\n * means NULL, and real symbols start at 2. This is exactly what the reader's\n * `decodeIndexColumn` undoes, and `writeBitField` is its inverse.\n *\n * The previous implementation went the long way round. Per cell it converted the raw value to\n * a QvdSymbol - a second time, the symbol table pass having already done it - to build a\n * template-literal lookup key, then turned the resulting index into a string of bits via\n * `toString(2).split('').map().reverse().concat().slice().reverse()`. Per row it kept an array\n * of those strings, padded each with `padStart`, reversed and joined them, split the result\n * with `/.{1,8}/g`, and allocated a Buffer; then `Buffer.concat` over one Buffer per row. On\n * the 1.7M-row taxi fixture that is 34 million symbols, 34 million key strings, 34 million bit\n * strings and 1.7 million Buffers, and it accounted for 98% of a write.\n *\n * Now: the widths are derived from the symbol counts, the offsets by prefix sum, one Buffer is\n * allocated for the whole table, and each value is OR-ed into place as an integer.\n *\n * @private\n */\n _buildIndexTable() {\n assert(this._symbolCounts, 'The QVD file symbol table has not been built.');\n assert(this._symbolTableMetadata, 'The QVD file symbol table metadata has not been built.');\n assert(this._symbolIndexByValue, 'The QVD file symbol index has not been built.');\n\n this._indexTableMetadata = [];\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numRows = data.length;\n const numColumns = columns.length;\n\n this._recordCount = numRows;\n this._emitProgress('index-table', 0, numRows);\n\n // Layout, one entry per column, hoisted out of the row loop so the inner loop does\n // arithmetic into a buffer and nothing else.\n /** @type {Array<{geometry: {byteStart: number, shift: number, byteCount: number}, nullShift: number}>} */\n const layout = [];\n\n let totalBits = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const fieldContainsNull = this._symbolTableMetadata[column][2];\n const symbolCount = this._symbolCounts[column];\n const nullShift = fieldContainsNull ? 2 : 0;\n\n // The largest stored index is (symbolCount - 1), shifted by 2 when the column contains\n // NULLs (index 0 denotes NULL and indices start at 2, which is what Bias=-2 encodes).\n //\n // Deriving the width this way is O(1) per column instead of O(rows), and it avoids\n // Math.max(...oneArgumentPerRow), which overflows the call stack somewhere around\n // 120k rows and made toQvd() unusable for realistic table sizes.\n const maxStoredIndex = symbolCount === 0 ? 0 : symbolCount - 1 + nullShift;\n\n // A single distinct value needs no bits at all, which matches what Qlik emits.\n const bitWidth = maxStoredIndex === 0 ? 0 : 32 - Math.clz32(maxStoredIndex);\n\n // Every index the row loop can write, checked once per column rather than once per cell.\n //\n // The row loop writes either 0, for NULL, or a value from these maps, so validating the\n // maps validates every write - 28,512 checks on the taxi fixture instead of 34 million,\n // and it covers the zero-width columns the per-cell check used to skip past. The bound is\n // the symbol count, not the field's capacity: a per-cell `storedIndex >= 2 ** bitWidth`\n // admitted indices in the gap between the two, which address no symbol. A reader before\n // #125 read them back without an error, and one after it refuses the file.\n const lookup = this._symbolIndexByValue[column];\n const maps =\n lookup.byCell === lookup.byKey\n ? [lookup.byKey, lookup.byObject]\n : [lookup.byCell, lookup.byKey, lookup.byObject];\n\n for (const map of maps) {\n for (const index of map.values()) {\n if (index + nullShift > maxStoredIndex) {\n throw new QvdValidationError('The symbol table and the index table are out of sync', {\n field: columns[column],\n storedIndex: index + nullShift,\n maxStoredIndex,\n symbolCount,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n }\n }\n\n layout.push({geometry: fieldGeometry(totalBits, bitWidth), nullShift});\n\n this._indexTableMetadata.push([totalBits, bitWidth, fieldContainsNull ? -2 : 0]);\n\n totalBits += bitWidth;\n }\n\n // Every column may have a bit width of 0 - each holds a single distinct value, or only\n // NULLs - leaving no bits at all. Qlik still uses a one-byte record in that situation, and\n // a zero-byte record would be rejected on read.\n const recordByteSize = Math.max(1, Math.ceil(totalBits / 8));\n\n this._recordByteSize = recordByteSize;\n this._indexBuffer = Buffer.alloc(numRows * recordByteSize);\n\n const progressInterval = Math.max(1, Math.floor(numRows / 100)); // Report progress every 1%\n\n // Hoisted, as in the symbol table pass, so a primitive cell costs array reads and one lookup, or none\n // for a number its column's table holds. A dual object has lookups of its own.\n const byCells = this._symbolIndexByValue.map((lookup) => lookup.byCell);\n const byKeys = this._symbolIndexByValue.map((lookup) => lookup.byKey);\n const byObjects = this._symbolIndexByValue.map((lookup) => lookup.byObject);\n // Tables of this pass's own rather than the symbol table pass's: sized for the numbers each column is\n // now known to hold, and filled only with what this pass's lookups return. src/util/seenNumbers.js's\n // opening comment says why that is enough, and which columns get none.\n const symbolCounts = this._symbolCounts;\n const wanted = this._symbolIndexByValue.map((lookup) => indexPassWants(lookup.numbers, lookup.cells));\n const share = shareOf(wanted.filter(Boolean).length);\n const pool = new SlotPool();\n const seen = this._symbolIndexByValue.map((lookup, column) =>\n wanted[column] ? indexPassTable(lookup.numbers, lookup.cells, symbolCounts[column], share, pool) : null,\n );\n const firstJudgement = firstJudgementRow(numRows);\n\n for (let row = 0, recordBase = 0; row < numRows; row++, recordBase += recordByteSize) {\n if ((row % WINDOW_ROWS === 0 && row !== 0) || row === firstJudgement) {\n endWindow(seen);\n }\n\n const values = data[row];\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n // NULL is stored index 0, which the bias turns back into a negative index on read.\n // Nothing to write: the buffer is already zeroed.\n continue;\n }\n\n const table = typeof value === 'number' ? seen[column] : null;\n /** @type {number|undefined} */\n let index;\n\n if (table !== null) {\n // A number the column has just looked up is found in its table, with the index the map gave it.\n table.cells++;\n const slot = slotOf(value, table.mask);\n\n if (table.values[slot] === value) {\n index = table.indices[slot];\n } else {\n index = byCells[column].get(value);\n\n // Only the map's own answer is remembered. A value it does not have is refused just below.\n if (index !== undefined) {\n table.values[slot] = value;\n table.indices[slot] = index;\n\n // A first sight is a miss no table could have avoided; only the others count against it.\n if (table.metBefore(index)) {\n table.misses++;\n }\n }\n }\n } else {\n // A dual object is remembered by identity up to a bound, and past it found by its number, which\n // the symbol table pass has already checked for this same object.\n index =\n typeof value === 'object'\n ? (byObjects[column].get(value) ?? byKeys[column].get(value.number))\n : byCells[column].get(value);\n }\n\n // A value the symbol table never saw. Unreachable while both passes walk the same rows,\n // which is the point of them sharing a counted loop - but the old code absorbed this\n // with `?? 0`, writing the first real symbol in place of the missing value, so a whole\n // column could read back as some other value with nothing thrown.\n if (index === undefined) {\n throw new QvdValidationError('A value is missing from the symbol table', {\n field: columns[column],\n row,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n\n writeBitField(this._indexBuffer, recordBase, layout[column].geometry, index + layout[column].nullShift);\n }\n\n // Report progress periodically\n if ((row + 1) % progressInterval === 0 || row + 1 === numRows) {\n this._emitProgress('index-table', row + 1, numRows);\n }\n }\n\n // The maps are dead once the table is packed, and the writer stays alive through the header\n // build and the file write - the point at which the symbol buffer and the index buffer are\n // both resident.\n this._symbolIndexByValue = null;\n }\n\n /**\n * Persists the data frame to a QVD file.\n */\n async save() {\n this._buildSymbolTable();\n this._buildIndexTable();\n this._buildHeader();\n await this._writeData();\n }\n}\n","// @ts-check\n\nimport os from 'os';\nimport v8 from 'v8';\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Gets the configured V8 heap size limit for the current Node.js process.\n * This respects the --max-old-space-size flag if set.\n *\n * @returns {number} Heap size limit in bytes\n */\nexport function getHeapLimit() {\n return v8.getHeapStatistics().heap_size_limit;\n}\n\n/**\n * Whether v8.getHeapStatistics().heap_size_limit means what it says on this runtime.\n *\n * Bun reports its *current* heap there rather than a ceiling - 229MB on a machine with 128GB of\n * RAM - so treating it as a limit rejects almost everything. It cannot be detected structurally\n * either: Bun spoofs both process.versions.v8 and process.versions.node, so the runtime's own\n * key is the only reliable signal.\n *\n * @return {boolean} True when the heap limit is a real limit.\n */\nfunction heapLimitIsMeaningful() {\n return !process.versions.bun && !process.versions.deno;\n}\n\n/**\n * Works out how much memory this process may actually use, and which limit decided it.\n *\n * Only two things can bind, and the smaller wins:\n *\n * - The V8 heap ceiling, which is what an allocation actually fails against, fatally and\n * uncatchably. V8 sizes it from physical memory by default, so it already scales down on a\n * small machine.\n * - A container memory limit, from process.constrainedMemory(). This is the case os.freemem()\n * gets dangerously wrong: inside a cgroup it reports the *host's* free memory, so a 2GB\n * container on a large host sails past the check and is then killed by the OOM killer with\n * exit 137 and no JavaScript error to catch.\n *\n * What the OS reports as free or available is deliberately *not* one of them. It is recorded for\n * diagnostics and ignored for the decision, because it does not describe a wall the process can\n * hit - a machine with virtual memory gets slower, not fatal - and because the number itself is\n * not trustworthy. os.freemem() counts only free and speculative pages, excluding the inactive\n * and file-cache pages the OS reclaims on demand. process.availableMemory() is meant to fix that\n * and does on Linux, but on macOS it depends on the libuv version underneath: Node 24 reported\n * 63GB on a 128GB machine here while Node 22 on a macOS CI runner reported 74MB, which refused a\n * 45MB load on a machine that had ample room for it. Letting either bind is what made the same\n * file load or fail from one minute, or one Node version, to the next.\n *\n * @return {{bytes: number, limitedBy: string, candidates: Array<{source: string, bytes: number}>,\n * observed: Array<{source: string, bytes: number}>}} The budget, the name of the limit that\n * bound it, what was allowed to bind, and what was recorded but not used.\n */\nexport function getMemoryBudget() {\n /** @type {Array<{source: string, bytes: number}>} */\n const candidates = [];\n\n if (heapLimitIsMeaningful()) {\n candidates.push({source: 'V8 heap limit', bytes: usableOldSpaceLimit()});\n }\n\n // Node returns 0 when the process is not constrained. Bun returns os.totalmem() instead, which\n // is not a constraint either, so anything at or above total memory is discarded rather than\n // treated as a container limit.\n const constrained = typeof process.constrainedMemory === 'function' ? process.constrainedMemory() : 0;\n if (constrained > 0 && constrained < os.totalmem()) {\n candidates.push({source: 'container memory limit', bytes: constrained});\n }\n\n // Bun outside a container has neither a usable heap limit nor a container limit, so without\n // this there would be no ceiling at all. Total memory is at least a real upper bound.\n if (candidates.length === 0) {\n candidates.push({source: 'total system memory', bytes: os.totalmem()});\n }\n\n /** @type {Array<{source: string, bytes: number}>} */\n const observed = [{source: 'free memory (os.freemem)', bytes: os.freemem()}];\n if (typeof process.availableMemory === 'function') {\n observed.push({source: 'available memory', bytes: process.availableMemory()});\n }\n\n const binding = candidates.reduce((lowest, candidate) => (candidate.bytes < lowest.bytes ? candidate : lowest));\n\n return {bytes: binding.bytes, limitedBy: binding.source, candidates, observed};\n}\n\n/**\n * What `heap_size_limit` overstates the usable old-space limit by, in bytes.\n *\n * `v8.getHeapStatistics().heap_size_limit` counts new space, code space and the trusted spaces\n * as well as old space, and it is old space that a row-materialising load exhausts. Measured on\n * this platform the gap is a flat 192MB at every configured size - `--max-old-space-size=96`\n * reports 288, 512 reports 704, 2048 reports 2240 - so it is an absolute offset, not a\n * proportion, and a safety factor cannot express it. At a 4GB heap it is under 5% and a factor\n * absorbs it; at a heap configured down to a couple of hundred megabytes it is most of the\n * budget, which is where an under-sized estimate turned into a crash.\n *\n * It used to be absorbed into the per-row constants instead, which made those constants\n * describe two unrelated things at once and left them four to six times larger than the memory\n * they were supposed to model. Subtracting it here lets the row model be a row model.\n *\n * V8 exposes no per-space limit - `getHeapSpaceStatistics()` reports current sizes, not\n * ceilings - so this is an observed constant rather than a derived one. If it is wrong on some\n * platform it is wrong in the safe direction on a large heap, and the safety factor still\n * applies underneath.\n */\nconst HEAP_LIMIT_OVERSTATEMENT_BYTES = 192 * 1024 * 1024;\n\n/**\n * Smallest budget worth reporting, in bytes.\n *\n * This is a damage limiter for a platform where the 192MB offset does not hold, not a\n * description of a real ceiling. Subtracting an offset that does not apply would leave a budget\n * near zero and refuse everything, so the floor catches that.\n *\n * It has to leave room for `BASE_BYTES` plus a small load *after* the safety factor, or it\n * achieves the opposite of its purpose. An earlier value of 16MB was exactly `BASE_BYTES`, so at\n * the floor the estimate always exceeded the budget and even `misc/small.qvd` - 606 rows, 29KB -\n * was refused on a runtime where it demonstrably loads. 64MB clears `BASE_BYTES` four times\n * over.\n *\n * It over-claims only where the true old-space limit is under 64MB, which is not a configuration\n * this library can serve: the fixed cost of reading any file at all is 15MB of that.\n */\nconst MINIMUM_BUDGET_BYTES = 64 * 1024 * 1024;\n\n/**\n * The heap limit, less the spaces a row load cannot use.\n *\n * A plain subtraction, because the overstatement is a flat offset at every configured size:\n * `--max-old-space-size=47` reports 239, 96 reports 288, 4096 reports 4288. An earlier version\n * of this only subtracted when the reported limit exceeded twice the offset and otherwise\n * returned half of it, which was meant to avoid a non-positive result. It instead produced the\n * wrong answer across the whole range the correction exists for: at a 47MB heap it returned\n * 119MB, so the guard admitted a load that needed 63MB and the process aborted - the exact\n * failure this function is here to prevent, reintroduced by the fallback rather than by the\n * rule.\n *\n * @return {number} Usable bytes.\n */\nfunction usableOldSpaceLimit() {\n const usable = getHeapLimit() - HEAP_LIMIT_OVERSTATEMENT_BYTES;\n\n return usable > MINIMUM_BUDGET_BYTES ? usable : MINIMUM_BUDGET_BYTES;\n}\n\n/**\n * Estimates the memory usage for loading a QVD file with given parameters.\n * Takes into account Phase 2.5 optimization which skips parsing unused symbols.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Rows the read covers (null = all rows). Decides how much of the\n * symbol table is parsed.\n * @param {number} totalRows Total number of rows in the file\n * @param {number} [columnCount] Columns per row.\n * @param {boolean} [materialisesRows] Whether rows are built at all.\n * @param {number|null} [rowsLive] Rows held at one instant, when that is fewer than `maxRows`.\n * Null means they are the same. Note that this is what the *caller* holds, not its chunk size:\n * `iterateRows` passes two chunks, because `for await` keeps the yielded frame reachable while\n * the generator builds the next one.\n * @returns {number} Estimated memory usage in bytes\n */\n/**\n * What a row-materialising load costs, in bytes.\n *\n * `BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columns)`.\n *\n * Recalibrated 2026-09-11, after the bitwise decode (#134) stopped the reader allocating an\n * array per row and several per cell. The method is the one the original calibration used:\n * generate N rows x C columns where every value is `(i + j) % 100`, so the symbol table stays\n * negligible and only row geometry moves, then binary-search the smallest\n * `--max-old-space-size` at which the load completes.\n *\n * shape cells was (pre-#134) now model\n * 400,000 x 10 4M 118 MB 63 77\n * 800,000 x 5 4M 237 MB 87 106\n * 200,000 x 40 8M 142 MB 79 62\n * 400,000 x 40 16M 307 MB 151 109\n * 800,000 x 20 16M 484 MB 175 202\n * 1,600,000 x 10 16M 520 MB 215 259\n *\n * and against two real files, which the original calibration did not cover:\n *\n * lego/inventory_parts 580,251 x 5 63 MB 81\n * chicago_taxi_rides 2016_01 1,705,805 x 20 367 MB 412\n *\n * The reader needs roughly 2.4x less heap than it did, which is why the old constants - 360 and\n * 34 - over-estimated a taxi read by 4.8x and refused loads that fit comfortably.\n *\n * Two of the model's figures sit *below* the measurement (200,000 x 40 and 400,000 x 40). That\n * is not an under-estimate of the rows: those two shapes are dominated by the fixed cost of\n * reading a file at all, which `BASE_BYTES` covers and which the per-row terms should not be\n * inflated to absorb. Every shape's total prediction is above its measured minimum.\n *\n * The constants are what the geometry implies rather than fitted numbers: a row is a JSArray\n * with a separate backing store, so it costs two object headers plus slack, and a cell is one\n * pointer. Fitting the eight measurements above gives 55-64 and 7.1-7.3; 72 and 8 clear every\n * one of them by 13-26%, which is the margin. Under-estimating means an uncatchable abort,\n * over-estimating means a catchable refusal, so the margin is deliberately one-sided.\n *\n * `BASE_BYTES` is what a load costs before any rows exist - the interpreter, the parsed header,\n * the decoded index columns. Measured as the floor of the binary search: a columnar read of any\n * of these files, which builds no rows at all, completes at 15MB.\n */\nconst BASE_BYTES = 16 * 1024 * 1024;\nconst ROW_BASE_BYTES = 72;\nconst PER_CELL_BYTES = 8;\n\n/**\n * Bytes a read allocates *outside* the V8 heap, in bytes.\n *\n * The decoder builds one `Int32Array` of stored indices per field, and a TypedArray's backing\n * store is external memory: it does not consume old space, so `--max-old-space-size` does not\n * bound it and the V8 heap budget must not be charged for it. A columnar read of the 38MB taxi\n * fixture completes in a 15MB heap for exactly this reason.\n *\n * A cgroup counts it, though, and exceeding a container limit is a SIGKILL - uncatchable, and\n * strictly worse than the heap abort this module exists to prevent. So it is estimated, and\n * checked against the container budget rather than the heap one.\n *\n * Both paths allocate it. A row read builds the codes and then the rows from them, so during\n * the load both are live; a columnar read keeps only the codes. The file buffer is external\n * too, but its size is not known here, and the codes dominate on the shapes that get close to\n * a limit.\n *\n * @param {number} rows Rows that will be decoded.\n * @param {number} columnCount Columns per row.\n * @return {number} Estimated external bytes.\n */\nexport function estimateExternalMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0 || !rows || rows <= 0) {\n return 0;\n }\n\n return rows * columnCount * Int32Array.BYTES_PER_ELEMENT;\n}\n\n/**\n * Estimates the heap a row-materialising load will need, in bytes.\n *\n * @param {number} rows Rows that will be materialised.\n * @param {number} columnCount Columns per row. Zero disables the term, for callers that do not\n * know the geometry yet.\n * @return {number} Estimated bytes.\n */\nfunction estimateRowMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0) {\n return 0;\n }\n return BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columnCount);\n}\n\nexport function estimateMemoryUsage(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount = 0,\n materialisesRows = true,\n rowsLive = null,\n wholeSymbols = false,\n) {\n // Memory overhead multipliers based on empirical testing\n const FULL_PARSE_OVERHEAD = 6.0; // Baseline: JavaScript objects have 6x overhead\n const MINIMAL_OVERHEAD = 0.01; // Skipped symbols: minimal null placeholder overhead\n\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n\n // Two different row counts, because two different things are being sized.\n //\n // `maxRows` is how many rows the read *covers*, and it is what decides how much of the symbol\n // table gets parsed - chunked iteration parses the symbol table once for the whole window, not\n // once per chunk. `rowsLive` is how many rows are materialised at the same instant, which is\n // what the heap actually has to hold: for a plain read they are the same number, and for\n // `iterate({chunkSize})` the second is *two* chunks of the first - `for await` keeps the\n // yielded frame reachable while the generator builds the next one, so two are alive at the\n // peak. Measured, because charging one chunk admitted a read that then aborted the process;\n // the caller computes the figure and passes it, this function only uses it.\n //\n // Conflating them is the failure this module has made before in the other direction - charging\n // a columnar read for rows it never builds. Charging a 20-million-row iteration for all 20\n // million rows when only `chunkSize` of them exist at once is the same mistake, and it would\n // refuse the one call shape that exists to make such a file readable at all.\n const liveRows = rowsLive === null ? rowsToLoad : Math.min(rowsLive, rowsToLoad);\n\n // The rows themselves. This term used to be missing entirely, which is what made the guard\n // useless for the commonest Qlik shape: many rows over low-cardinality fields. A 150MB file\n // with a 0.43MB symbol table was estimated at 2.6MB and then killed a default heap.\n //\n // A columnar read materialises none of them, and what it does allocate - one Int32Array of\n // codes per field - is a TypedArray backing store, which lives outside the V8 heap this\n // budget describes. That is not a modelling nicety: binary-searching the smallest\n // --max-old-space-size at which a columnar read completes gives 15MB for every file tried,\n // from a 4MB fixture to the 38MB taxi one, because almost nothing it allocates is on the\n // heap. Charging it the row cost refused columnar reads that need a fortieth of the budget.\n const rowMemory = materialisesRows ? estimateRowMemory(liveRows, columnCount) : BASE_BYTES;\n\n if (maxRows === null || maxRows >= totalRows || wholeSymbols) {\n // Loading all rows - need all symbols, no filtering benefit.\n //\n // `wholeSymbols` says the same thing for a read that covers a window: the discount below models the\n // two-pass path, where a symbol no row of the window uses is walked past without being decoded. A\n // paging read turns that path off, because a column decoded for one page is kept for the next and a\n // column decoded in part would answer `undefined` for a row a later page asks about. So it holds\n // every symbol of every column it has touched, and charging it a square root of them was an\n // under-estimate - the direction that ends in a heap-limit abort rather than an error.\n return symbolTableSize * FULL_PARSE_OVERHEAD + rowMemory;\n }\n\n // Estimate what percentage of symbols we'll need\n // Symbol usage grows slower than linear (diminishing returns as you add rows)\n // Use square root scaling as empirical approximation\n const rowPercentage = maxRows / totalRows;\n const symbolPercentage = Math.sqrt(rowPercentage);\n\n // Calculate memory for kept symbols (full overhead) + skipped symbols (minimal overhead)\n const keptSymbolsMemory = symbolTableSize * symbolPercentage * FULL_PARSE_OVERHEAD;\n const skippedSymbolsMemory = symbolTableSize * (1 - symbolPercentage) * MINIMAL_OVERHEAD;\n\n return keptSymbolsMemory + skippedSymbolsMemory + rowMemory;\n}\n\n/**\n * Finds the largest row count whose estimate fits inside a budget.\n *\n * The estimate is monotonic in rows but not invertible in closed form - the symbol term scales\n * with sqrt(rows/totalRows) while the row term scales linearly - so this bisects instead, and\n * the answer is therefore a value the caller can actually use. The previous implementation\n * inverted the square-root term alone and suggested row counts that the same check rejected on\n * the next call.\n *\n * When the limit that refused the read bounds the whole process rather than the V8 heap, the\n * external term has to be counted here too. Without it the suggestion is bisected against a\n * different quantity from the one the refusal used - and for a columnar read, whose heap estimate\n * barely moves with rows, the first test succeeds and it hands back the exact row count it just\n * refused. Recommending the input that produced the error is worse than recommending nothing.\n *\n * @param {number} budget Bytes available.\n * @param {number} symbolTableSize Size of the symbol table in bytes.\n * @param {number} totalRows Rows the file declares.\n * @param {number} columnCount Columns per row.\n * @param {boolean} [materialisesRows=true] Whether rows are built at all.\n * @param {boolean} [includeExternal=false] Count TypedArray backing stores, for a limit that\n * bounds the process rather than old space.\n * @return {number} A row count whose estimate fits the budget, or 0 when none does.\n */\nexport function recommendedRowsFor(\n budget,\n symbolTableSize,\n totalRows,\n columnCount,\n materialisesRows = true,\n includeExternal = false,\n wholeSymbols = false,\n) {\n const costOf = (/** @type {number} */ rows) =>\n estimateMemoryUsage(symbolTableSize, rows, totalRows, columnCount, materialisesRows, null, wholeSymbols) +\n (includeExternal ? estimateExternalMemory(Math.min(rows, totalRows), columnCount) : 0);\n\n if (costOf(totalRows) <= budget) {\n return totalRows;\n }\n\n // The bisection below treats `low` as a value known to fit, so that has to be true of its\n // starting point. It is not automatic: the estimate charges 1% of the symbol table even when\n // no rows are requested, so a symbol table two orders of magnitude larger than the budget\n // leaves nothing that fits. Clamping the answer up to 1 in that case produced a suggestion\n // the caller could not use - `maxRows: 1` threw the same error it had just been offered as\n // the fix for.\n if (costOf(0) > budget) {\n return 0;\n }\n\n let low = 0;\n let high = totalRows;\n while (high - low > 1) {\n const mid = Math.floor((low + high) / 2);\n if (costOf(mid) <= budget) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Finds the largest chunk size whose estimate fits inside a budget.\n *\n * The sibling of `recommendedRowsFor`, for the one caller whose knob is not the window. Chunked\n * iteration parses the symbol table once for the whole window however small the chunks are, so\n * the window is held fixed here and only the live-row term moves - bisecting the window instead\n * would recommend a number that does not correspond to anything the caller can set.\n *\n * The answer is in the caller's units, which is why `liveRowsPerChunk` has to be given rather\n * than assumed to be one: the iterator holds two chunks at a time, so bisecting live rows and\n * calling the result a chunk size would recommend a chunk twice as large as fits - and the caller\n * would be refused again on the very next call, which is the loop this function exists to avoid.\n *\n * @param {number} budget Bytes available.\n * @param {number} symbolTableSize Size of the symbol table in bytes.\n * @param {number|null} windowRows Rows the iteration covers, which fixes the symbol term.\n * @param {number} totalRows Rows the file declares.\n * @param {number} columnCount Columns per row.\n * @param {number} [liveRowsPerChunk=1] Rows alive per row of chunk size.\n * @param {boolean} [includeExternal=false] Count TypedArray backing stores, for a limit that\n * bounds the process rather than old space - see `recommendedRowsFor`.\n * @param {boolean} [wholeSymbols=false] Whether the read holds every symbol of the columns it touches\n * rather than only those its window uses - true for a paging read. It has to reach here as well as\n * the answer: advice priced with the discount that the answer refused without it is advice the very\n * next call rejects.\n * @return {number} A chunk size whose estimate fits the budget, or 0 when none does.\n */\nexport function recommendedChunkFor(\n budget,\n symbolTableSize,\n windowRows,\n totalRows,\n columnCount,\n liveRowsPerChunk = 1,\n includeExternal = false,\n wholeSymbols = false,\n) {\n const covered = windowRows === null || windowRows >= totalRows ? totalRows : windowRows;\n\n const fits = (/** @type {number} */ chunk) => {\n const live = Math.min(chunk * liveRowsPerChunk, covered);\n const cost =\n estimateMemoryUsage(\n symbolTableSize,\n windowRows,\n totalRows,\n columnCount,\n true,\n chunk * liveRowsPerChunk,\n wholeSymbols,\n ) + (includeExternal ? estimateExternalMemory(live, columnCount) : 0);\n\n return cost <= budget;\n };\n\n if (fits(covered)) {\n return covered;\n }\n\n // A chunk of one row is the smallest thing a caller can ask for. If even that does not fit,\n // the symbol table alone has exhausted the budget and no chunk size helps - say so rather than\n // returning a number the very next call rejects.\n if (!fits(1)) {\n return 0;\n }\n\n let low = 1;\n let high = covered;\n while (high - low > 1) {\n const mid = Math.floor((low + high) / 2);\n if (fits(mid)) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * A read that holds no bytes of the file, for a caller that declares none.\n *\n * One shape rather than two, so every use of the charge below is a field access. It used to accept a\n * plain number as well, which every use then had to branch on, and which let a test give one function\n * for both knobs and so prove nothing about which of them priced an answer.\n */\nconst noBytesHeld = Object.freeze({held: 0, forRows: () => 0, forChunk: () => 0});\n\n/**\n * Validates that there is sufficient memory available to load a QVD file safely.\n * Considers both available system RAM and the configured V8 heap limit.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} [safetyFactor=0.8] Fraction of the memory budget to use (0.0-1.0). Zero\n * disables the check entirely.\n *\n * The default was 0.3 while the estimate counted only the symbol table - a proxy that\n * understated real cost by around a hundredfold for the commonest Qlik shape, so the factor was\n * quietly compensating for it. Now that the estimate models the rows too, 0.3 would double-count\n * that margin and refuse loads with four times the headroom they need. The estimate sits about\n * 1.2-1.6x above the measured requirement, so 0.8 still leaves V8 room to collect.\n * @param {number} [columnCount=0] Columns per row, so the estimate can account for the row\n * arrays. Zero omits that term, which is what the old symbol-table-only estimate did.\n * @param {boolean} [materialisesRows=true] Whether this read builds row arrays at all.\n * @param {{rows: number, perChunk: number}|null} [live=null] For a read that holds fewer rows at\n * once than it covers: `rows` is how many are alive at the peak, and `perChunk` how many of\n * those one row of the caller's chunk size accounts for, so a refusal can name a chunk size.\n * Null means the read holds everything it covers, which is every read but chunked iteration.\n * @param {{held: number, forRows: (rows: number) => number, forChunk: (rows: number) => number}|null}\n * [bytesHeld=null] Bytes of file the read holds outside the heap while it works: the symbol areas it\n * reads, and the one buffer its records come through. Counted with the codes, against a limit that\n * bounds the process rather than old space. `held` is this read's; `forRows` and `forChunk` say what a\n * read of so many rows, or of so many rows a chunk, would hold instead, so that each suggestion is\n * priced at its own record buffer rather than at this read's or at the other suggestion's. `null` and\n * `undefined` both mean a read that holds nothing of the file.\n * @param {number|null} [readBytes=null] Bytes the read will read from the file, carried into the\n * answer so that a refusal's `check` says everything a pre-flight would have said.\n * @throws {QvdValidationError} If insufficient memory is available\n */\nexport function validateMemoryAvailability(\n symbolTableSize,\n maxRows,\n totalRows,\n filePath,\n safetyFactor = 0.8,\n columnCount = 0,\n materialisesRows = true,\n live = null,\n bytesHeld = null,\n readBytes = null,\n wholeSymbols = false,\n retainedBytes = 0,\n) {\n const answer = checkMemory({\n wholeSymbols,\n retainedBytes,\n symbolTableSize,\n maxRows,\n totalRows,\n safetyFactor,\n columnCount,\n materialisesRows,\n live,\n bytesHeld,\n readBytes,\n });\n\n if (answer.fits) {\n return;\n }\n\n const {message, context} = answer.refusal;\n\n // The same message and the same context keys this has always thrown, so a caller matching on\n // either is unaffected - with `reason` and `check` added beside them. `check` is the whole answer\n // a pre-flight would have given for this read, so a caller that did not ask beforehand gets it\n // from the refusal rather than having to ask again.\n throw new QvdValidationError(message, {\n file: filePath,\n ...context,\n reason: 'memory',\n check: answerOf(answer),\n });\n}\n\n/**\n * What a read would cost, and whether it fits, without refusing it.\n *\n * The same computation the refusal is built from - deliberately the same, because a pre-flight that\n * answered a different question from the one the read asks is worse than no pre-flight at all. A read\n * this approves is not refused later for memory, and every suggestion it offers has been read back\n * through it.\n *\n * @param {object} params What the read will do.\n * @param {number} params.symbolTableSize Bytes of symbols the read will read - the areas of the fields\n * it selects, not the table they sit in.\n * @param {number|null} params.maxRows Rows the window covers, or null for every row.\n * @param {number} params.totalRows Rows the file declares.\n * @param {number} [params.safetyFactor=0.8] Fraction of the budget the read may use. Zero disables the\n * check, and makes this answer `fits` with no estimate to stand behind it.\n * @param {number} [params.columnCount=0] Columns the read builds.\n * @param {boolean} [params.materialisesRows=true] Whether it builds row arrays at all.\n * @param {{rows: number, perChunk: number}|null} [params.live=null] Rows held at one instant when that\n * is fewer than the window covers - chunked iteration, and nothing else.\n * @param {{held: number, forRows: (rows: number) => number, forChunk: (rows: number) => number}|null}\n * [params.bytesHeld=null] Bytes of the file the read holds outside the heap - see\n * `validateMemoryAvailability`.\n * @param {number|null} [params.readBytes=null] Bytes it will read from the file, for the answer's\n * estimate. It does not enter the decision: reading is not holding.\n * @param {boolean} [params.wholeSymbols=false] Whether the read decodes every symbol of the columns it\n * touches rather than only those its window uses - true for a paging read, which keeps what it\n * decodes and so cannot decode a column in part.\n * @param {number} [params.retainedBytes=0] Of `symbolTableSize`, the bytes belonging to columns an\n * earlier read decoded and kept that this one does not select - what letting go of the file would\n * release without changing what this read needs. It decides whether a refusal is the cache's fault,\n * which `wholeSymbols` cannot: that is true from the moment paging is switched on, before any page\n * has decoded anything.\n * @param {any} [params.measured=null] A budget already measured by `getMemoryBudget`, for a caller\n * asking several questions at once. Sizing a suggestion means asking again, and asking again\n * re-measured the budget each time - so a suggestion was checked against a slightly different budget\n * from the answer that prompted it, and a wide file paid for a `v8.getHeapStatistics()` call per\n * column. Passing one in makes the whole set of questions one measurement.\n * @return {{fits: boolean, reason?: string, estimate: {heapBytes: number, externalBytes: number,\n * readBytes: number|null}, budget: {heapBytes: number, processBytes: number|null, bound: string,\n * safetyFactor: number, allowedBytes: number, candidates: Array<{source: string, bytes: number}>,\n * observed: Array<{source: string, bytes: number}>}, exact: boolean,\n * suggestions: Array<{option?: string, nodeOption?: string, value: any}>,\n * refusal?: {message: string, context: object}}} The answer.\n */\nexport function checkMemory({\n symbolTableSize,\n maxRows,\n totalRows,\n safetyFactor = 0.8,\n columnCount = 0,\n materialisesRows = true,\n live = null,\n bytesHeld = null,\n readBytes = null,\n measured = null,\n wholeSymbols = false,\n retainedBytes = 0,\n}) {\n if (typeof safetyFactor !== 'number' || safetyFactor < 0 || safetyFactor > 1) {\n throw new QvdValidationError('safetyFactor must be a number between 0.0 and 1.0', {\n safetyFactor,\n reason: 'option',\n option: 'memorySafetyFactor',\n value: safetyFactor,\n });\n }\n\n // Zero disables the check. It used to mean a budget of zero bytes, which refused every file\n // however small - not something any caller can have wanted - so the only reading that makes it\n // useful is \"I will manage memory myself\". This is the documented escape hatch for runtimes\n // whose limits cannot be measured, and for callers who know better than the estimate.\n //\n // It fits by definition rather than by measurement, and the answer says so through `safetyFactor: 0`\n // and an `allowedBytes` of Infinity - not by reporting a cost of nothing. What a read would cost does\n // not depend on whether anything is enforcing a limit, and the estimate is arithmetic on the header\n // rather than a measurement, so it is as good here as anywhere. Returning zeros made the pre-flight\n // answer \"it costs nothing\" for every read by a caller who had turned enforcement off, which is the\n // one question it exists to answer. What is skipped below is the decision, not the estimate.\n const budget = measured ?? getMemoryBudget();\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n\n // `live` describes a read that holds fewer rows at once than it covers - chunked iteration, and\n // nothing else so far. `rows` is how many are alive at the peak; `perChunk` is how many of them\n // one row of the caller's chunk size buys, so that a refusal can recommend a chunk size rather\n // than a live-row count. Both come from the same caller in the same call, so they cannot\n // describe different reads.\n const rowsLive = live === null ? null : live.rows;\n const liveRowsPerChunk = live === null ? 1 : live.perChunk;\n\n // The codes are allocated for whatever is decoded at once, which is one chunk under chunked\n // iteration and the whole window otherwise - the same distinction the heap estimate draws, and\n // it has to be drawn in both places or the two halves of the check describe different reads.\n const liveRows = rowsLive === null ? rowsToLoad : Math.min(rowsLive, rowsToLoad);\n const heapMemory = estimateMemoryUsage(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount,\n materialisesRows,\n rowsLive,\n wholeSymbols,\n );\n\n // The codes, and the bytes the read holds while it parses them: the symbol areas it reads and the one\n // buffer its records come through. All three are TypedArray or Buffer storage, which does not occupy old\n // space but does count against a container, so they are charged where the codes are.\n //\n // `held` is what this read holds; `forRows` and `forChunk` say what a read following either piece of\n // advice would hold instead, which is what the suggestions below need. The symbol areas do not move with\n // the row count, but the record buffer does, shrinking with the rows until it is one slice no longer, so\n // a suggestion priced at this read's buffer is one the next call refuses.\n //\n // Two functions, because the two knobs move different things. A smaller `limit` is a smaller window;\n // a smaller `chunkSize` is the same window decoded in smaller pieces. `forRows` and `forChunk` are that\n // distinction, and using one where the other belongs is how the chunk advice came to be priced at a read\n // that does not exist.\n //\n // `noBytesHeld` covers a caller that says nothing - `null` as much as `undefined`, since a default fires\n // only for the second and an argument list of nulls is how a caller says \"nothing to declare\" here.\n const {\n held,\n afterRelease: heldAfterRelease = null,\n forRows: heldForRows,\n forChunk: heldForChunk,\n } = bytesHeld ?? noBytesHeld;\n const externalMemory = estimateExternalMemory(liveRows, columnCount) + held;\n\n // Each candidate is measured against the memory it actually bounds. The V8 heap limit bounds\n // old space, which TypedArray backing stores do not occupy; a container limit bounds the\n // process, which they do. Checking one figure against both was wrong in both directions at\n // once: it refused columnar reads that fit the heap forty times over, and - once that was\n // fixed by not charging them for rows - it admitted a columnar read allocating 130MB of codes\n // inside a container with less than that, where the kernel answers with a SIGKILL.\n const bounded = budget.candidates.map((candidate) => {\n const heapOnly = candidate.source === 'V8 heap limit';\n\n return {\n ...candidate,\n heapOnly,\n needs: heapOnly ? heapMemory : heapMemory + externalMemory,\n allowed: candidate.bytes * safetyFactor,\n bounds: heapOnly ? 'the V8 heap' : 'the whole process',\n };\n });\n\n // The candidate closest to binding, whether or not it binds. One rule for both branches, because\n // `bound` and `allowedBytes` describe the same candidate either way: on a refusal it is the one that\n // refused, and on an answer that fits it is the one with the least room left. They used to be worked\n // out two different ways - the worst ratio when refusing, the smallest allowance when fitting - so the\n // same two fields meant different things depending on the answer, and a caller could not compare the\n // estimate against the allowance without knowing which branch had produced it.\n if (safetyFactor === 0) {\n const lowest = budget.candidates.reduce((least, candidate) => (candidate.bytes < least.bytes ? candidate : least));\n\n return {\n fits: true,\n estimate: {heapBytes: heapMemory, externalBytes: externalMemory, readBytes},\n // The ceilings are still there and still named - what is missing is any measurement against them.\n // An earlier version reported `bound: 'none'` here, a third value in a two-value vocabulary that a\n // caller switching on the documented two would fall straight through.\n budget: {\n ...budgetOf(budget, {...lowest, heapOnly: lowest.source === 'V8 heap limit'}, 0),\n allowedBytes: Infinity,\n },\n exact: symbolTableSize === 0,\n suggestions: [],\n };\n }\n\n const tightest = bounded.reduce((worst, candidate) =>\n candidate.needs / candidate.allowed > worst.needs / worst.allowed ? candidate : worst,\n );\n const binding = tightest.needs > tightest.allowed ? tightest : null;\n\n const heapLimit = getHeapLimit();\n const availableMemory = binding ? binding.bytes : budget.bytes;\n const estimatedMemory = binding ? binding.needs : heapMemory;\n const maxAllowedMemory = binding ? binding.allowed : budget.bytes * safetyFactor;\n\n // Whether the columns an earlier read left behind are what refused this one - which is a different\n // question from whether paging is on. `wholeSymbols` is true from `beginPaging()` onwards, so\n // branching on it told a first page, and a `check()` made before any page, that previously decoded\n // columns were to blame and that closing the file would release them. Nothing was held, closing\n // released nothing, and the retry failed identically.\n //\n // The honest test is counterfactual: take the retained columns out of the estimate and see whether\n // what is left fits. Only then is letting go of them a remedy rather than a distraction.\n const retainedIsTheReason = (() => {\n if (binding === null || retainedBytes <= 0) {\n return false;\n }\n\n const heapAfter = estimateMemoryUsage(\n Math.max(0, symbolTableSize - retainedBytes),\n maxRows,\n totalRows,\n columnCount,\n materialisesRows,\n rowsLive,\n wholeSymbols,\n );\n // Not `externalMemory - retainedBytes`: the retained columns were never in it. `bytesHeld` is built\n // from the areas this read still has to read, which excludes anything cached, so subtracting them\n // removed bytes nobody had charged and made releasing look like a cure more often than it is.\n // `afterRelease` is the honest figure, and it is the larger one.\n const externalAfter = estimateExternalMemory(liveRows, columnCount) + (heldAfterRelease ?? held);\n\n // Every candidate, not just the one binding now. Releasing heap-held columns can leave a different\n // ceiling binding - a container limit that the external bytes of rereading them reach - and telling\n // a caller to reopen when the reopened read is refused by something else is the same wrong advice\n // one step along.\n return budget.candidates.every((candidate) => {\n const heapOnly = candidate.source === 'V8 heap limit';\n\n return (heapOnly ? heapAfter : heapAfter + externalAfter) <= candidate.bytes * safetyFactor;\n });\n })();\n\n if (binding) {\n // Bisected against the same estimate this check uses, so the suggestion is one the caller\n // can act on. It used to invert the square-root symbol term alone and could suggest a row\n // count that the very next call rejected.\n // Bisected against the same quantity the refusal compared, which for a process-bounded limit\n // includes the external term. A suggestion measured against a different budget from the\n // refusal is the same mismatch this module exists to avoid, one level up.\n const includeExternal = !binding.heapOnly;\n\n // The bytes of file come off the budget the suggestion is bisected against, rather than out of the\n // estimate, because the symbols do not move with the row count. The record buffer does: a read holding\n // fewer rows reads fewer records at a time, until it is one slice no longer. So the budget has to be\n // the one the suggestion itself would hold against, and one pass does not find it.\n //\n // `fitting` falls as its argument rises, since a larger read holds a larger buffer and leaves less of\n // the budget for rows. A row count is therefore one the next call accepts exactly when\n // `rows <= fitting(rows)`, and applying `fitting` alternates about that line: `firstGuess`, priced at\n // this read's charge, satisfies it; `over` is the larger answer that smaller charge allows, and does\n // not; `under` is `over` priced at its own charge, and satisfies it again. The advice is the larger of\n // the two that hold, so it is both a row count that fits and no smaller than the cautious first pass.\n //\n // Bisected once against this read's charge alone, the answer could be \"no row count fits\" where a\n // smaller read fitted. Bisected twice, it overshot instead: 8MB of symbols, a 16MB slice and 64 bytes\n // a row in a 32MB container advised 4,449 rows, and 4,449 rows was refused by the very next call -\n // the loop this module exists to avoid, one level up.\n const rowsHeldBudget = (/** @type {number} */ rows) => maxAllowedMemory - (includeExternal ? heldForRows(rows) : 0);\n const fitting = (/** @type {number} */ rows) =>\n recommendedRowsFor(\n rowsHeldBudget(rows),\n symbolTableSize,\n totalRows,\n columnCount,\n materialisesRows,\n includeExternal,\n wholeSymbols,\n );\n const firstGuess = fitting(liveRows);\n const over = fitting(firstGuess);\n const under = fitting(over);\n const recommendedMaxRows = Math.max(firstGuess, under);\n\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const availableMB = Math.round(maxAllowedMemory / 1024 / 1024);\n // The usable figure, not the reported one. These differ by the 192MB of non-old-space\n // that heap_size_limit counts, and printing the reported one next to a budget breakdown\n // carrying the corrected one told the reader two different things about the same limit -\n // in the one diagnostic whose job is to say which knob to turn.\n const heapLimitMB = Math.round(usableOldSpaceLimit() / 1024 / 1024);\n const reportedHeapLimitMB = Math.round(heapLimit / 1024 / 1024);\n const availableRamMB = Math.round(availableMemory / 1024 / 1024);\n\n // Naming the limit that bound the decision is the difference between an actionable error and\n // a puzzling one: raising --max-old-space-size fixes a heap-bound refusal and does nothing\n // for a container-bound one, where it makes the OOM kill more likely rather than less.\n // The bare source name, because callers match it against memoryBudget[].source - a test\n // pins that. What the limit bounds goes in its own field and into the prose.\n const limitingFactor = binding.source;\n const limitingScope = binding.bounds;\n const budgetBreakdown = budget.candidates\n .map((candidate) => `${candidate.source} ${Math.round(candidate.bytes / 1024 / 1024)}MB`)\n .join(', ');\n const observedBreakdown = budget.observed\n .map((entry) => `${entry.source} ${Math.round(entry.bytes / 1024 / 1024)}MB`)\n .join(', ');\n\n // Saying \"try maxRows: N\" when no N fits sends the caller round a loop, so that case gets its\n // own advice rather than a number that will be rejected on the next call.\n //\n // A chunked read gets a different knob named, because the one it has is not the window. Its\n // window may be the whole file by design, and shrinking it is not what the caller wants to\n // hear when what actually overflowed is one chunk.\n //\n // It is bisected exactly as the row count above is, and for the same reason, but against its own\n // charge: `forChunk`, not `forRows`. A chunk is not a row count - `chunkSize` leaves the window where\n // it is - so pricing the advice at a row count's buffer was pricing it at a read that does not exist.\n // On 1MB of symbols, 40-byte records and two columns of a million rows in a 48MB container, that\n // advised a chunk of 74,730 rows and then refused it; across a sweep of 1,104 refusals that carried\n // chunk advice, 299 came back refused.\n const containerBound = binding.source === 'container memory limit';\n const chunked = rowsLive !== null;\n const chunkHeldBudget = (/** @type {number} */ rows) =>\n maxAllowedMemory - (includeExternal ? heldForChunk(rows) : 0);\n const chunkFitting = (/** @type {number} */ rows) =>\n recommendedChunkFor(\n chunkHeldBudget(rows),\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount,\n liveRowsPerChunk,\n includeExternal,\n wholeSymbols,\n );\n // The caller's own chunk is the starting point, as this read's row count was for the row advice.\n const callersChunk = chunked ? Math.max(1, Math.floor(rowsLive / Math.max(1, liveRowsPerChunk))) : 0;\n const firstChunk = chunked ? chunkFitting(callersChunk) : 0;\n const overChunk = chunked ? chunkFitting(firstChunk) : 0;\n const recommendedChunk = chunked ? Math.max(firstChunk, chunkFitting(overChunk)) : 0;\n const knob = chunked ? 'chunkSize' : 'limit';\n const recommendedValue = chunked ? recommendedChunk : recommendedMaxRows;\n const nothingFits = recommendedValue === 0;\n\n // What the fixed cost of this read actually is, which is not always the file's symbol table. A paging\n // read is charged for every column any of its pages has decoded and kept, so on a wide file the part\n // that does not fit is usually what the caller is still holding rather than anything about the file.\n // Saying \"the symbol table alone exceeds it\" there was untrue - 2MB of symbols against a 24MB budget,\n // with 28MB needed - and it named the one remedy that does not help, because raising the limit is not\n // what a caller who has paged across twenty columns should reach for first.\n const held = retainedIsTheReason;\n // The verb travels with the phrase, because one subject is plural and the other is not.\n const fixedCost = held ? 'the columns this file is holding exceed' : 'the symbol table alone exceeds';\n const release = held ? `Close the file and open it again to release them, or raise ` : `Raise `;\n\n // Named in every branch a cache-caused refusal can reach, not only the one where nothing fits. A\n // page can be refused with a smaller page still available *and* the columns being held still the\n // reason, and that caller was told to shrink the page or raise a limit without being told the one\n // thing that would give them the whole page back. Direct remedy first, fallbacks after.\n const releaseFirst = held\n ? `Close the file and open it again to release the columns it is holding, which is the direct remedy. `\n : '';\n\n let advice;\n if (nothingFits) {\n advice =\n `No row count fits this budget - ${fixedCost} it, so ${knob} cannot help. ` +\n (containerBound\n ? `${release}the container's memory limit.`\n : `${release}the heap with --max-old-space-size, or raise memorySafetyFactor.`);\n } else if (containerBound) {\n advice =\n releaseFirst +\n `The binding limit is the container's, so raising --max-old-space-size would let V8 grow past it and be killed by the OOM killer instead. Set it below the container limit, raise the limit, or hold fewer rows with ${knob} (recommended: ${formatCount(recommendedValue)} rows or less).`;\n } else {\n advice =\n releaseFirst +\n `Try holding fewer rows using the ${knob} parameter (recommended: ${formatCount(recommendedValue)} rows or less), or raise the heap with --max-old-space-size.`;\n }\n\n // Every suggestion is read back through this same check before it is offered - that is what the\n // bisections above do - so following one gives a read that fits. A `fields` suggestion is the one\n // this function cannot make: it does not know what each field costs, only what the selection does.\n // `checkRead` makes it, from the header, and adds it.\n const suggestions = [];\n\n if (!nothingFits) {\n suggestions.push({option: knob, value: recommendedValue});\n }\n\n // Raising the heap is advice only where the heap is what bound it. Under a container limit it makes\n // the kill more likely rather than less, which is what the prose above says at length.\n if (!containerBound) {\n // `--max-old-space-size=N` makes `getHeapLimit()` report about N plus the overstatement, and\n // `usableOldSpaceLimit()` takes the overstatement back off - so the usable budget is N itself, and\n // adding the overstatement here counted it twice. It asked for 192MB more than the read needs,\n // every time.\n //\n // Checked rather than asserted, like every other suggestion: the value is the smallest whole\n // megabyte whose budget covers the estimate, and the loop below steps up until it does, so the\n // arithmetic above cannot be subtly wrong without the answer being wrong too.\n let needed = Math.ceil(estimatedMemory / safetyFactor / (1024 * 1024));\n\n while (Math.max(needed * 1024 * 1024, MINIMUM_BUDGET_BYTES) * safetyFactor < estimatedMemory) {\n needed += 1;\n }\n\n suggestions.push({nodeOption: '--max-old-space-size', value: needed});\n }\n\n return {\n fits: false,\n reason: 'memory',\n estimate: {heapBytes: heapMemory, externalBytes: externalMemory, readBytes},\n budget: budgetOf(budget, tightest, safetyFactor),\n // The symbol term is six times the bytes on disk, an overhead measured across files rather than\n // derived, so any read with symbols in it is an estimate and says so. Only a read that decodes\n // nothing can be exact.\n exact: symbolTableSize === 0,\n suggestions,\n refusal: {\n message:\n `Insufficient memory to load file safely. ` +\n `${retainedIsTheReason ? 'Columns held' : 'Symbol table'}: ${sizeMB}MB, Estimated memory needed: ${estimatedMB}MB, Available: ${availableMB}MB (limited by ${limitingFactor}, which bounds ${limitingScope}; considered: ${budgetBreakdown}; observed but not used: ${observedBreakdown}). ` +\n advice,\n context: {\n symbolTableSize,\n symbolTableSizeMB: sizeMB,\n // Whether that figure is the file's symbol table or what an open file is still holding. A\n // paging read is charged for every column any of its pages decoded and kept, so a caller\n // branching on the refusal needs to know which of the two it is looking at - the remedies\n // differ, and for this one releasing is a remedy where raising the limit is only a workaround.\n holdsDecodedColumns: retainedIsTheReason,\n retainedSymbolBytes: retainedBytes,\n estimatedMemoryMB: estimatedMB,\n availableMemoryMB: availableMB,\n heapLimitMB,\n reportedHeapLimitMB,\n availableRamMB,\n limitingFactor,\n limitingScope,\n memoryBudget: budget.candidates,\n memoryObserved: budget.observed,\n columnCount,\n totalRows,\n maxRows,\n recommendedMaxRows,\n // Only present when a chunk size is what overflowed, so a caller cannot mistake one\n // recommendation for the other.\n ...(chunked ? {rowsLive, recommendedChunkSize: recommendedChunk} : {}),\n },\n },\n };\n }\n\n return {\n fits: true,\n estimate: {heapBytes: heapMemory, externalBytes: externalMemory, readBytes},\n budget: budgetOf(budget, tightest, safetyFactor),\n exact: symbolTableSize === 0,\n suggestions: [],\n };\n}\n\n/**\n * The documented half of an answer: everything but the refusal the wrapper throws from.\n *\n * @param {any} answer The answer `checkMemory` returned.\n * @return {any} The same, without `refusal`.\n */\nfunction answerOf(answer) {\n // eslint-disable-next-line no-unused-vars\n const {refusal, ...rest} = answer;\n\n return rest;\n}\n\n/**\n * The budget half of an answer, built the same way whether the read fits or not.\n *\n * `bound` and `allowedBytes` both describe `tightest`, so they cannot disagree with each other, and\n * `processBytes` is whatever candidate bounds the process rather than only a container's - on a runtime\n * with no usable heap limit the process is bounded by total system memory, and reporting `bound` as\n * `process` beside a `processBytes` of null said two things about one answer.\n *\n * @param {{candidates: Array<{source: string, bytes: number}>, observed: Array<{source: string,\n * bytes: number}>}} budget What `getMemoryBudget` measured.\n * @param {{source: string, bytes: number, heapOnly: boolean, allowed?: number}} tightest The candidate\n * with the least room left.\n * @param {number} safetyFactor The fraction of it this read may use.\n * @return {any} The budget half.\n */\nfunction budgetOf(budget, tightest, safetyFactor) {\n // Not named `process`: this module reads `process.constrainedMemory()` and `process.versions`, and a\n // local of that name here would shadow the global for anything added to this function later.\n const processLimit = budget.candidates.find((candidate) => candidate.source !== 'V8 heap limit');\n\n return {\n heapBytes: usableOldSpaceLimit(),\n processBytes: processLimit ? processLimit.bytes : null,\n bound: tightest.heapOnly ? 'heap' : 'process',\n safetyFactor,\n allowedBytes: tightest.allowed ?? tightest.bytes * safetyFactor,\n candidates: budget.candidates,\n observed: budget.observed,\n };\n}\n\n/**\n * Formats a row count for a human reading a diagnostic.\n *\n * Pinned to `en-US` rather than left to `toLocaleString()`'s default, which follows the host's\n * locale. The messages here are English prose, so a number grouped by the machine's convention was\n * inconsistent with the sentence around it - and worse, it made the same message differ between\n * platforms: `9,999,999` on the Linux and macOS runners against `9 999 999` on the Windows ones,\n * where the separator is a narrow no-break space. That is invisible until something matches on the\n * text. A test of this module's warning did, and passed everywhere it was run before failing all\n * three Windows legs in CI.\n *\n * The same property matters outside tests: a diagnostic that reads the same on every platform is\n * one a caller can grep for in a log aggregator collecting from all three.\n *\n * @param {number} value The count.\n * @return {string} The count, grouped the same way everywhere.\n */\nfunction formatCount(value) {\n return value.toLocaleString('en-US');\n}\n\n/**\n * Emits a warning for large symbol tables when loading all rows.\n * Warning threshold scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {number} [columnCount=0] Columns per row, so the reported figure matches the check\n */\nexport function warnLargeSymbolTable(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount = 0,\n materialisesRows = true,\n wholeSymbols = false,\n) {\n // Dynamic warning threshold: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n // 12.5% of the budget the check uses, not of the figure v8 reports. Thresholding on the\n // reported limit made the warning fire later than the refusal it is meant to precede, and by\n // the widest margin on the small heaps where the 192MB of non-old-space is most of it.\n const LARGE_SYMBOL_TABLE_WARNING = usableOldSpaceLimit() * 0.125;\n\n if (symbolTableSize <= LARGE_SYMBOL_TABLE_WARNING) {\n return;\n }\n\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n // Same estimate the check uses. Without columnCount this printed the symbol table's cost\n // alone - roughly 3.6GB where the check had just computed 5.2GB - and a caller sizing\n // --max-old-space-size from the warning would pick a heap far too small.\n const estimatedMemory = estimateMemoryUsage(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount,\n materialisesRows,\n null,\n wholeSymbols,\n );\n\n // The second condition is the cost of *this* read, not whether the caller happened to bound it.\n //\n // It used to be `maxRows === null || maxRows >= totalRows` - \"you asked for everything\". That is\n // a statement about which option was passed, and it came apart when `offset` arrived:\n // `{offset: 1}` on a ten-million-row file materialises 9,999,999 rows and reports a row count\n // one short of the total, so the warning about the memory that costs was silent in exactly the\n // case it exists for. Thresholding the estimate instead is the same answer for every shape that\n // existed before - a full read still warns, a small `maxRows` still does not, because the symbol\n // term is discounted by sqrt(rows/totalRows) - and it is right for the shapes that did not.\n if (estimatedMemory <= LARGE_SYMBOL_TABLE_WARNING) {\n return;\n }\n\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const warnMB = Math.round(LARGE_SYMBOL_TABLE_WARNING / 1024 / 1024);\n\n console.warn(\n `⚠️ Large symbol table detected (${sizeMB}MB > ${warnMB}MB threshold). ` +\n `This read materialises ${formatCount(rowsToLoad)} of ${formatCount(totalRows)} rows ` +\n `and will use ~${estimatedMB}MB RAM. ` +\n `Reading fewer rows - with limit, maxRows, or a narrower offset window - lowers the row cost, ` +\n `though the symbol table is read in full either way.`,\n );\n}\n","// @ts-check\n\nimport {QvdCorruptedError, QvdValidationError} from '../QvdErrors.js';\nimport {getHeapLimit} from './memoryUtils.js';\nimport {MAX_BIT_WIDTH} from './bitUtils.js';\n\n/**\n * A number from the header, read as the whole number it is written as, or NaN when it is not written as\n * one.\n *\n * `parseInt` read the longest prefix it could: `1e18` as 1, `605.9` as 605, `0x10` as 0, and an element\n * written twice - which xml2js hands over as an array - as its first value, because the array stringifies\n * with commas. Each read as an ordinary number. `readMetadata` reported a 606-row file as holding 1, 605\n * or 0 rows, and a `BitOffset` written twice read 389 of `misc/small.qvd`'s 606 cells from the wrong\n * bits, with nothing thrown.\n *\n * Qlik writes every number in a header as plain decimal digits - all 216 fields of the 30 Qlik-written\n * QVDs in the repository do - and so does this library. Whitespace around the digits is allowed: xml2js\n * keeps it, and it cannot be read two ways.\n *\n * NaN rather than a throw, so each number keeps the validator, and the message, it already had. Every\n * number the reader takes from a header comes through here, which is also what stops `readMetadata` and\n * the reads that decode rows from reading one header two ways.\n *\n * @param {unknown} value The element's value, as xml2js gives it.\n * @return {number} The number, or NaN. Never -0.\n */\nexport function headerInteger(value) {\n if (typeof value !== 'string' || !/^\\s*-?\\d+\\s*$/.test(value)) {\n return NaN;\n }\n\n const number = Number(value);\n\n // `-0` is a whole number, and means the zero every comparison below expects.\n return number === 0 ? 0 : number;\n}\n\n/**\n * Validates that a parsed XML header actually describes a QVD, and returns its fields.\n *\n * `parseStringPromise` succeeds on any well-formed XML, and a QVD whose header has been damaged\n * into a fragment parses into an object rooted at whatever element survived - `{Thou: ''}` for\n * `__tests__/data/misc/damaged.qvd`. The `!headerObj` check beside each call site only covers XML\n * that did not parse at all, so the reader indexed straight into a missing `QvdTableHeader` and\n * raised a bare `TypeError`, reporting an ordinary corrupt file as a bug in this library.\n *\n * `Offset` is range-checked here because nothing downstream checks it: an unusable one makes the\n * index table offset NaN, which `_planIndexTable` reads as falsy and reports as the file having\n * been loaded out of order. `RecordByteSize` and `NoOfRecords` are deliberately left alone -\n * `validateIndexTableMetadata` and `validateRecordCount` already reject both the missing and the\n * malformed cases with a more specific message, and repeating the check here would replace it\n * with a vaguer one.\n *\n * The field list is checked here as well, and every field's name. Both places that parse a header\n * call this, and the first - the one a read of rows makes before it reads anything large - resolves\n * the caller's field selection against the names, before the second has run. Checked only in the\n * second, a missing name met that selection first and was reported as a column the caller had asked\n * for wrongly, rather than as a broken header.\n *\n * @param {any} headerObj The parsed XML header.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} stage Stage name recorded in the error context.\n * @return {Array<any>} Every field header, in file order.\n * @throws {QvdCorruptedError} If the header is not a usable QVD table header.\n */\nexport function validateHeaderStructure(headerObj, filePath, stage) {\n const tableHeader = headerObj?.['QvdTableHeader'];\n\n // `typeof null` is 'object' and an empty `<QvdTableHeader/>` parses to '' rather than to an\n // object, so neither case is caught by a truthiness or a typeof test on its own.\n if (tableHeader === null || typeof tableHeader !== 'object' || Array.isArray(tableHeader)) {\n throw new QvdCorruptedError('The XML header contains no usable QvdTableHeader element', {\n rootElements: headerObj && typeof headerObj === 'object' ? Object.keys(headerObj) : [],\n file: filePath,\n stage,\n });\n }\n\n const symbolTableLength = headerInteger(tableHeader['Offset']);\n\n if (isNaN(symbolTableLength) || !Number.isSafeInteger(symbolTableLength) || symbolTableLength < 0) {\n throw new QvdCorruptedError('Invalid symbol table offset', {\n offset: tableHeader['Offset'],\n file: filePath,\n stage,\n });\n }\n\n // A header with no field elements, validated here rather than at each use.\n //\n // Three places downstream normalised the field list with `if (!Array.isArray(fields)) fields =\n // [fields]`, which turns an absent `<Fields/>` into `[undefined]` and then dereferences it - a bare\n // TypeError from the middle of the reader where readMetadata, which checked, reported the file as\n // corrupt. A header that declares no fields is a broken header, not a table with no columns, and\n // `columnCount: 0` for it would be a plausible answer to the wrong question.\n const fields = tableHeader['Fields']?.['QvdFieldHeader'];\n const fieldList = fields === undefined || fields === null ? [] : Array.isArray(fields) ? fields : [fields];\n\n if (fieldList.length === 0) {\n throw new QvdCorruptedError('The QVD file header declares no fields', {\n file: filePath,\n stage,\n });\n }\n\n // Counting the entries is not enough, because a `<QvdFieldHeader>` that is empty or holds text\n // instead of child elements parses to a string, and the normalisation above counts a string as one\n // perfectly good field. Nothing then reads it as anything but an object: readMetadata reported\n // `columns: [null], columnCount: 1` for an eight-column file, which is indistinguishable from a real\n // one-column QVD, while fromQvd refused the same file as corrupt several steps later and blamed a\n // symbol offset. That divergence is the thing the metadata path is designed not to produce, so the\n // entries are checked where they are counted.\n const malformedIndex = fieldList.findIndex(\n (field) => field === null || typeof field !== 'object' || Array.isArray(field),\n );\n\n if (malformedIndex !== -1) {\n throw new QvdCorruptedError('The QVD file header declares a field with no properties', {\n fieldIndex: malformedIndex,\n fieldCount: fieldList.length,\n file: filePath,\n stage,\n });\n }\n\n // Every field needs a name, and one no other field has.\n //\n // A missing name read as an `undefined` column, and one holding an element as an object; a\n // `<FieldName>` written twice read as an array. Two fields of one name read as two columns of it,\n // and `at(row, name)`, `select(name)` and a `fields` selection answered about the first and ignored\n // the second - which is why `selectFields` refuses a name listed twice. Every read reports the\n // names, readMetadata included, so every read refuses them. None of the Qlik-written QVDs in the\n // repository has either, and this library's writer refuses both.\n /** @type {Map<string, number>} */\n const seen = new Map();\n\n fieldList.forEach((field, fieldIndex) => {\n const name = field['FieldName'];\n\n if (typeof name !== 'string' || name === '') {\n throw new QvdCorruptedError('The QVD file header declares a field with no usable name', {\n fieldIndex,\n fieldName: name,\n file: filePath,\n stage,\n });\n }\n\n if (seen.has(name)) {\n throw new QvdCorruptedError('The QVD file header declares two fields with the same name', {\n field: name,\n fieldIndexes: [seen.get(name), fieldIndex],\n file: filePath,\n stage,\n });\n }\n\n seen.set(name, fieldIndex);\n });\n\n return fieldList;\n}\n\n/**\n * Validates symbol table size during initial file read (early check).\n * This is the first-pass validation in _readData for lazy loading.\n * Limit scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} [retainedBytes=0] Of `symbolTableLength`, the bytes belonging to columns an earlier\n * read decoded and kept that this one does not select. It decides whether the columns being held are\n * what breached the ceiling - which \"is this a paging read\" cannot answer, since that is true from the\n * moment paging is switched on and before any page has decoded anything.\n * @throws {QvdValidationError} If symbol table exceeds dynamic limit\n */\nexport function validateSymbolTableSizeEarly(symbolTableLength, filePath, retainedBytes = 0) {\n // Dynamic limit: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n const heapLimit = getHeapLimit();\n const MAX_SYMBOL_TABLE_SIZE = heapLimit * 0.125;\n\n if (symbolTableLength > MAX_SYMBOL_TABLE_SIZE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(MAX_SYMBOL_TABLE_SIZE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n // A paging read reaches this with what its pages have decoded and kept, not with the file's table, so\n // the standard advice is wrong twice over for it: the cardinality is not the point, and \"load the\n // full file without a row window\" is the opposite of what a caller paging a 30 GB file wants. What\n // helps there is letting go of the columns already held.\n // Only when letting go of them would bring it back under. A first page whose own column is too big\n // is over the ceiling on its own, and telling that caller to close and reopen sends them round a\n // loop: nothing is released and the retry breaches it again at the same number.\n if (retainedBytes > 0 && symbolTableLength - retainedBytes <= MAX_SYMBOL_TABLE_SIZE) {\n throw new QvdValidationError(\n `Columns held too large (${sizeMB}MB exceeds ${maxMB}MB limit). ` +\n `This open file is holding the columns its pages have decoded, and they have grown past the ` +\n `ceiling rather than the file's own symbol table being large. ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 12.5% = ${maxMB}MB). ` +\n `Consider: (1) closing the file and opening it again, which releases what the pages decoded, ` +\n `(2) paging over fewer columns with fields, or (3) increasing heap size with --max-old-space-size.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n holdsDecodedColumns: true,\n retainedSymbolBytes: retainedBytes,\n maxAllowed: MAX_SYMBOL_TABLE_SIZE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n reason: 'memory',\n },\n );\n }\n\n throw new QvdValidationError(\n `Symbol table too large (${sizeMB}MB exceeds ${maxMB}MB limit for lazy loading). ` +\n `This QVD file contains extremely high-cardinality fields. ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 12.5% = ${maxMB}MB). ` +\n // \"without a row window\" rather than \"without maxRows\": a window can be spelled with\n // maxRows, limit, offset, or an offset and a limit together, and all four reach this\n // check. Naming one of them tells a caller who passed `offset` to remove something they\n // did not pass.\n `Consider: (1) loading the full file without a row window - maxRows, limit or offset - since the symbol table is read in full either way, (2) increasing heap size with --max-old-space-size, or (3) aggregating high-cardinality fields.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n // Present and false, not absent. A caller told it can branch on this has to find it on both\n // refusals, or the branch reads `undefined` for the commoner of the two.\n holdsDecodedColumns: false,\n retainedSymbolBytes: retainedBytes,\n maxAllowed: MAX_SYMBOL_TABLE_SIZE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 12.5,\n },\n );\n }\n}\n\n/**\n * Validates symbol table size limits to prevent out-of-memory conditions.\n * This is the comprehensive validation in _parseSymbolTable.\n * Absolute ceiling scales with configured heap size (50% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} totalRows Total number of rows in the file\n * @throws {QvdValidationError} If symbol table exceeds safety limits\n */\nexport function validateSymbolTableSize(symbolTableLength, filePath, totalRows) {\n // Dynamic absolute ceiling: 50% of configured heap size\n // Examples: 4GB heap = 2GB, 8GB heap = 4GB, 16GB heap = 8GB, 32GB heap = 16GB\n const heapLimit = getHeapLimit();\n const ABSOLUTE_MAX_SYMBOL_TABLE = heapLimit * 0.5;\n\n if (symbolTableLength > ABSOLUTE_MAX_SYMBOL_TABLE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(ABSOLUTE_MAX_SYMBOL_TABLE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table exceeds absolute maximum size (${sizeMB}MB > ${maxMB}MB). ` +\n `This QVD file has pathological cardinality (likely a data modeling issue). ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 50% = ${maxMB}MB). ` +\n `Consider: (1) increasing heap size with --max-old-space-size, (2) aggregating high-cardinality fields, (3) splitting the data, or (4) using a different format.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: ABSOLUTE_MAX_SYMBOL_TABLE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 50,\n totalRows,\n },\n );\n }\n}\n\n/**\n * Validates field metadata before processing to prevent buffer overflow attacks.\n *\n * The symbol area has to be inside the symbol table, and `NoOfSymbols` has to be a whole number. Whether\n * the area holds that many symbols is for the parse to find out, which is the only thing that walks them.\n * A count that cannot even be read is refused here, for every field, like an unreadable `Offset` or\n * `Length`, so a read of other fields only does not accept a header the full read refuses.\n *\n * @param {any} field Field metadata object\n * @param {number} symbolBufferLength Length of the symbol buffer\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field metadata is invalid\n */\nexport function validateFieldMetadata(field, symbolBufferLength, filePath) {\n const symbolsOffset = headerInteger(field['Offset']);\n const symbolsLength = headerInteger(field['Length']);\n const symbolCount = headerInteger(field['NoOfSymbols']);\n\n // Validate offset is a valid number and within bounds\n if (isNaN(symbolsOffset) || !Number.isSafeInteger(symbolsOffset) || symbolsOffset < 0) {\n throw new QvdCorruptedError('Invalid symbol offset', {\n field: field['FieldName'],\n offset: symbolsOffset,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate length is a valid number and non-negative\n if (isNaN(symbolsLength) || !Number.isSafeInteger(symbolsLength) || symbolsLength < 0) {\n throw new QvdCorruptedError('Invalid symbol length', {\n field: field['FieldName'],\n length: symbolsLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate the symbol count is a valid number and non-negative\n if (isNaN(symbolCount) || !Number.isSafeInteger(symbolCount) || symbolCount < 0) {\n throw new QvdCorruptedError('Invalid symbol count', {\n field: field['FieldName'],\n noOfSymbols: symbolCount,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate that offset + length doesn't exceed buffer size\n if (symbolsOffset + symbolsLength > symbolBufferLength) {\n throw new QvdCorruptedError('Symbol data extends beyond buffer', {\n field: field['FieldName'],\n offset: symbolsOffset,\n length: symbolsLength,\n bufferSize: symbolBufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n}\n\n/**\n * A field's claim on a range of bytes or bits: where it starts, and how many it takes.\n *\n * @typedef {Object} FieldRange\n * @property {string} field The field's name.\n * @property {number} start The first byte or bit.\n * @property {number} length How many.\n */\n\n/**\n * The first two of a set of ranges that overlap, or null when none do.\n *\n * Empty ranges are left out, because they claim nothing: every field of `misc/empty_qvd.qvd` starts its\n * symbols at byte 0 with none to hold, and two of them are zero bits wide at bit 0.\n *\n * @param {Array<FieldRange>} ranges The ranges, in field order.\n * @return {[FieldRange, FieldRange]|null} The range reaching furthest so far, and the first to start\n * inside it. Ranges that start together are taken in field order.\n */\nfunction firstOverlap(ranges) {\n const claimed = ranges.filter((range) => range.length > 0).sort((a, b) => a.start - b.start);\n /** @type {FieldRange|null} */\n let furthest = null;\n\n for (const range of claimed) {\n if (furthest !== null && range.start < furthest.start + furthest.length) {\n return [furthest, range];\n }\n\n if (furthest === null || range.start + range.length > furthest.start + furthest.length) {\n furthest = range;\n }\n }\n\n return null;\n}\n\n/**\n * Validates that no two fields' symbol areas overlap.\n *\n * Each field's symbols are read from the area its `Offset` and `Length` give, and `validateFieldMetadata`\n * checks only that the area is inside the symbol table. Two fields whose areas overlap each read some of\n * the same bytes as their own symbols: `ProductName` pointed at `ProductKey`'s area in `misc/small.qvd`\n * read all 606 of its values as `ProductKey`'s, with nothing thrown, because every index still addressed\n * a symbol. Qlik lays the areas end to end, in field order, from byte 0, and so does this library.\n *\n * Only an overlap is refused. A gap between two areas takes nothing from either field. An area cut short\n * leaves its field fewer symbols, and a row that points past them is refused where it is decoded.\n *\n * Call it once `validateFieldMetadata` has passed every field, which is what makes the numbers usable.\n *\n * @param {Array<any>} fields Every field header in the file.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If two fields' symbol areas overlap.\n */\nexport function validateSymbolAreas(fields, filePath) {\n const overlap = firstOverlap(\n fields.map((field) => ({\n field: field['FieldName'],\n start: headerInteger(field['Offset']),\n length: headerInteger(field['Length']),\n })),\n );\n\n if (overlap !== null) {\n const [first, second] = overlap;\n\n throw new QvdCorruptedError('Symbol areas overlap', {\n field: second.field,\n offset: second.start,\n length: second.length,\n overlaps: first.field,\n overlapsOffset: first.start,\n overlapsLength: first.length,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n}\n\n/**\n * Validates that no two fields' bits overlap within a record.\n *\n * Each field's stored index is read from the bits its `BitOffset` and `BitWidth` give, and\n * `validateFieldBitMetadata` checks only that they are inside the record. Two fields whose bits overlap\n * each read some of the same bits as their own: `Weight`'s bits pointed at `ListPrice`'s in\n * `misc/small.qvd` read 391 of its 606 values wrong, with nothing thrown, wherever `ListPrice`'s index\n * was also one of `Weight`'s symbols. Qlik packs a record's fields without overlaps, though not in field\n * order, and so does this library; a field zero bits wide claims no bits at all.\n *\n * Call it once `validateFieldBitMetadata` has passed every field, which is what makes the numbers usable.\n *\n * @param {Array<any>} fields Every field header in the file.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If two fields' bits overlap.\n */\nexport function validateBitFields(fields, filePath) {\n const overlap = firstOverlap(\n fields.map((field) => ({\n field: field['FieldName'],\n start: headerInteger(field['BitOffset']),\n length: headerInteger(field['BitWidth']),\n })),\n );\n\n if (overlap !== null) {\n const [first, second] = overlap;\n\n throw new QvdCorruptedError('Bit fields overlap', {\n field: second.field,\n bitOffset: second.start,\n bitWidth: second.length,\n overlaps: first.field,\n overlapsBitOffset: first.start,\n overlapsBitWidth: first.length,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n\n/**\n * Validates a header's declared record count.\n *\n * Extracted so the metadata-only read applies exactly the same rule as a load. When they were\n * separate, `readMetadata` coerced an unusable `NoOfRecords` to zero while `fromQvd` refused the\n * same file - so a header with the element deleted reported \"0 rows\" rather than \"this header is\n * broken\", which is indistinguishable from a genuinely empty QVD at the call site.\n *\n * @param {number} totalRows The parsed NoOfRecords.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} [stage='parseIndexTable'] Stage name recorded in the error context.\n * @throws {QvdCorruptedError} If the count is not a non-negative safe integer.\n */\nexport function validateRecordCount(totalRows, filePath, stage = 'parseIndexTable') {\n if (isNaN(totalRows) || !Number.isSafeInteger(totalRows) || totalRows < 0) {\n throw new QvdCorruptedError('Invalid number of records', {\n totalRows,\n file: filePath,\n stage,\n });\n }\n}\n\n/**\n * Validates a header's declared record size.\n *\n * Extracted, like `validateRecordCount`, so a windowed read refuses an unusable one with the message a\n * whole-file read gives. A windowed read has to check it before it sizes the buffer the window is read\n * into, which is earlier than `validateIndexTableMetadata` runs, and it used to say `Invalid header value:\n * RecordByteSize` there - one header, two answers, depending on the window a caller asked for.\n *\n * @param {number} recordSize The parsed RecordByteSize.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} [stage='parseIndexTable'] Stage name recorded in the error context.\n * @throws {QvdCorruptedError} If the size is not a non-negative safe integer.\n */\nexport function validateRecordSize(recordSize, filePath, stage = 'parseIndexTable') {\n if (isNaN(recordSize) || !Number.isSafeInteger(recordSize) || recordSize < 0) {\n throw new QvdCorruptedError('Invalid record byte size', {\n recordSize,\n file: filePath,\n stage,\n });\n }\n}\n\n/**\n * Validates index table metadata and bounds.\n *\n * @param {number} recordSize Size of a single record in bytes\n * @param {number} totalRows Total number of rows\n * @param {number} indexTableLength Length of the index table\n * @param {number} indexTableOffset Offset to the index table\n * @param {number} bufferLength Length of the buffer\n * @param {number} rowsToLoad Number of rows to load\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number|null} [fileSize] Actual size of the file on disk, when known. Used to detect a\n * header that describes more data than the file contains.\n * @param {number} [windowFirstRow=0] File row the decode starts at. The rows before it still have\n * to exist in the declared table, so the table has to reach `windowFirstRow + rowsToLoad`.\n * @param {number} [bufferFirstRow=0] File row the loaded buffer's index table starts at. A\n * windowed read loads only the records it wants, so this is not always zero, and the two row\n * numbers bound different things: the first bounds the file, the second bounds the buffer.\n * @throws {QvdCorruptedError} If index table metadata is invalid\n */\nexport function validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n indexTableOffset,\n bufferLength,\n rowsToLoad,\n filePath,\n fileSize = null,\n windowFirstRow = 0,\n bufferFirstRow = 0,\n) {\n validateRecordSize(recordSize, filePath);\n validateRecordCount(totalRows, filePath);\n\n // Allow recordSize of 0 or 1 only when there are no records (empty QVD)\n // Qlik Sense uses recordSize=1 for empty QVDs\n if (recordSize === 0 && totalRows > 0) {\n throw new QvdCorruptedError('Record byte size cannot be zero when records exist', {\n recordSize,\n totalRows,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate recordSize is reasonable (max 1MB per record)\n if (recordSize > 1048576) {\n throw new QvdCorruptedError('Record byte size exceeds maximum', {\n recordSize,\n maxSize: 1048576,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table length\n if (isNaN(indexTableLength) || !Number.isSafeInteger(indexTableLength) || indexTableLength < 0) {\n throw new QvdCorruptedError('Invalid index table length', {\n length: indexTableLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table start offset doesn't extend beyond buffer\n if (indexTableOffset > bufferLength) {\n throw new QvdCorruptedError('Index table offset beyond buffer', {\n indexTableOffset,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // The index table must be exactly as long as the record count implies. Every QVD produced by\n // Qlik or by this library satisfies this, so a mismatch means the header is inconsistent.\n // Checking it catches corrupt headers that would otherwise decode misaligned rows.\n if (indexTableLength !== totalRows * recordSize) {\n throw new QvdCorruptedError('Index table length inconsistent with record count', {\n indexTableLength,\n expectedLength: totalRows * recordSize,\n totalRows,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate the index table against the actual file when its size is known.\n //\n // Comparing against the in-memory buffer instead is wrong in both directions: during a lazy\n // load the buffer is deliberately truncated, so valid large files were rejected as corrupt,\n // while a truncated file whose header claims more data was accepted and silently returned\n // fewer rows than the header declares.\n if (fileSize !== null) {\n if (indexTableOffset + indexTableLength > fileSize) {\n throw new QvdCorruptedError('Index table extends beyond the end of the file', {\n indexTableOffset,\n indexTableLength,\n fileSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n }\n\n // Ensure the loaded buffer actually holds the rows we were asked to parse.\n //\n // The window's records start `(windowFirstRow - bufferFirstRow)` records into the buffer's index\n // table, which is zero for a read that starts at row 0 and not zero for one that does not.\n const requiredIndexBytes = rowsToLoad * recordSize;\n const bufferRecordStart = (windowFirstRow - bufferFirstRow) * recordSize;\n if (indexTableOffset + bufferRecordStart + requiredIndexBytes > bufferLength) {\n throw new QvdCorruptedError('Index table truncated', {\n indexTableOffset,\n requiredBytes: requiredIndexBytes,\n availableBytes: Math.max(0, bufferLength - indexTableOffset - bufferRecordStart),\n rowsToLoad,\n windowFirstRow,\n bufferFirstRow,\n recordSize,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Ensure the index table reaches the end of the window, not merely as far as its length.\n //\n // Measured against the window's last row rather than its row count: `{offset: 10, limit: 5}`\n // needs fifteen records to exist, and comparing five against the table's length would accept a\n // file that holds only twelve - decoding three real rows and two of whatever follows.\n const requiredTableBytes = (windowFirstRow + rowsToLoad) * recordSize;\n if (indexTableLength < requiredTableBytes) {\n throw new QvdCorruptedError('Index table length smaller than required', {\n indexTableLength,\n requiredBytes: requiredTableBytes,\n rowsToLoad,\n windowFirstRow,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n\n/**\n * Validates a field's bit offset, bit width and bias for index table parsing.\n *\n * @param {any} field Field metadata object\n * @param {number} recordSize Size of a single record in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field bit metadata is invalid\n */\nexport function validateFieldBitMetadata(field, recordSize, filePath) {\n const bitOffset = headerInteger(field['BitOffset']);\n const bitWidth = headerInteger(field['BitWidth']);\n\n // Validate bitOffset\n if (isNaN(bitOffset) || !Number.isSafeInteger(bitOffset) || bitOffset < 0) {\n throw new QvdCorruptedError('Invalid bit offset', {\n field: field['FieldName'],\n bitOffset,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth\n if (isNaN(bitWidth) || !Number.isSafeInteger(bitWidth) || bitWidth < 0) {\n throw new QvdCorruptedError('Invalid bit width', {\n field: field['FieldName'],\n bitWidth,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias.\n //\n // It is added to every decoded index inside an Int32Array, and Int32Array coerces NaN to 0 -\n // so an absent or non-numeric Bias made a file read back as plausible wrong values rather\n // than as an error. A blank <Bias> on a nullable column turned every NULL and every symbol\n // above the first into the first symbol, silently. Validated here alongside the other two\n // because the three travel together and are trusted together.\n const bias = headerInteger(field['Bias']);\n\n if (isNaN(bias) || !Number.isSafeInteger(bias)) {\n throw new QvdCorruptedError('Invalid bias', {\n field: field['FieldName'],\n bias: field['Bias'],\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth against what a stored index can be.\n //\n // Indices are kept in an Int32Array, so the value has to fit in a positive 32-bit integer.\n // The bound is not a limitation in practice - 31 bits addresses two billion symbols in one\n // field - and refusing is the safe direction: a 32-bit width lets the top of the range wrap\n // to a negative index, which read back as NULL before #125, so the file returned plausible\n // wrong values rather than an error.\n if (bitWidth > MAX_BIT_WIDTH) {\n throw new QvdCorruptedError('Bit width exceeds maximum', {\n field: field['FieldName'],\n bitWidth,\n maxBitWidth: MAX_BIT_WIDTH,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias against what an index can be once it is applied.\n //\n // A field's indices run from `Bias` to `Bias + 2^BitWidth - 1`, and they are kept in an\n // Int32Array, which stores a value outside 32 bits modulo 2^32 rather than refusing it. A wrapped\n // index is not an error but a different index: a Bias of 2^32 - 2 decodes exactly as -2 does, and\n // on `misc/small.qvd` it turned 604 of a column's 606 values into other symbols and two into\n // NULLs, with nothing thrown. Below -2^31 the same wrap turns what should be negative - NULL -\n // into a real symbol. Refusing the Bias is what lets every later check trust that the index it\n // looks at is the one the file holds.\n if (bias < -(2 ** 31) || bias + 2 ** bitWidth - 1 > 2 ** 31 - 1) {\n throw new QvdCorruptedError('Bias out of range', {\n field: field['FieldName'],\n bias,\n bitWidth,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias against the two values a QVD uses.\n //\n // Qlik writes 0 for a field without NULLs and -2 for one with them - 207 and 9 of the 216 fields in\n // the 30 Qlik-written QVDs in the repository - and so does this library. Any other value that fits in\n // 32 bits passed every check above and shifted the column. A Bias of 0 read as -1 turned stored index 0\n // into the NULL marker and every other index into its neighbour's symbol: `misc/small.qvd`'s Color read\n // all 606 of its values wrong, 254 of them as NULL, and no read threw, because every index still\n // addressed a symbol or NULL. -1 is also the one other value a writer might choose on purpose, with NULL\n // at stored index 0 and symbols from 1, and no rule can refuse the damage and keep that, so it is refused\n // too. Checked after the range above, so a Bias that would wrap keeps that diagnosis.\n if (bias !== 0 && bias !== -2) {\n throw new QvdCorruptedError('Bias is neither 0 nor -2', {\n field: field['FieldName'],\n bias,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitOffset + bitWidth doesn't exceed record size in bits\n const recordSizeInBits = recordSize * 8;\n if (bitOffset + bitWidth > recordSizeInBits) {\n throw new QvdCorruptedError('Bit field extends beyond record size', {\n field: field['FieldName'],\n bitOffset,\n bitWidth,\n recordSizeInBits,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n","// @ts-check\n\nimport assert from 'assert';\nimport {QvdCorruptedError, QvdParseError} from '../QvdErrors.js';\n\n/**\n * The longest text one symbol may hold. A damaged file cannot then make the reader decode a string the\n * size of the whole symbol table.\n */\nconst MAX_TEXT_BYTES = 1048576;\n\n/**\n * One field's symbols, as the two halves each can have, decoded straight from the symbol table's bytes.\n *\n * A pure number has a number and no text, a pure string a text and no number, and a dual both. A symbol\n * the two-pass path did not need has neither: nothing was decoded for it, and every symbol a file holds\n * has at least one half, so null in both cannot be mistaken for a value.\n *\n * Two arrays per field rather than an object per symbol. The reader resolves what each symbol reads as\n * from these, once, and nothing else keeps them; a high-cardinality field used to allocate a symbol\n * object, a result object and two typed arrays for every numeric value it held.\n *\n * A read reports what the file holds, unchecked: a damaged file's NaN double reads as NaN, and it is the\n * writer that refuses to store it again.\n *\n * @typedef {Object} FieldSymbols\n * @property {Array<number|null>} numbers Each symbol's number: an int's, a double's or a dual's.\n * @property {Array<string|null>} texts Each symbol's text: a string's or a dual's.\n */\n\n/**\n * How far a search for a text's terminator may reach, and how far into its view the walk may go before\n * the view moves.\n *\n * `Buffer.prototype.indexOf` misreports any position past 2^31 - 1, whether it is where the search\n * starts or where the byte is found. On Node 22 and 24 it returns the position less 2^32, a large\n * negative number, where it should return the index or -1. A symbol area can be larger than that - one\n * field of 2.1 million texts of 1,100 characters is 2.3 GB - and the walk read the negative number as a\n * terminator, moved its position back before the area, and threw a raw `TypeError` on the `undefined` it\n * found there (#122). So on an area larger than `reach` a search runs on a view of at most `reach` bytes,\n * and the view moves up to the current position once the walk is more than `rebaseAfter` bytes into it.\n *\n * `reach` must exceed `rebaseAfter` by more than `MAX_TEXT_BYTES`, so a view always holds as much of a\n * text as the text may hold: a terminator it does not find belongs to a text too long to be read anyway.\n * A parameter rather than a constant only so a test can make it small, and walk every bundled file across\n * many moves, which no test could do at 2 GiB.\n */\nexport const TEXT_SEARCH = Object.freeze({reach: 2 ** 31 - 1, rebaseAfter: 2 ** 30});\n\n/**\n * A search for the next NUL in `area` that stays correct past 2^31 - see `TEXT_SEARCH`.\n *\n * An area no larger than `reach` is searched directly, as it always was.\n *\n * @param {Buffer} area The symbol table up to the end of one field's area.\n * @param {{reach: number, rebaseAfter: number}} limits The view's longest reach, and when it moves.\n * @return {(from: number) => number} Finds the first NUL at or after `from`, and returns its index in\n * `area`, or -1 when the view holds none.\n */\nfunction nulFinder(area, {reach, rebaseAfter}) {\n assert(reach - rebaseAfter > MAX_TEXT_BYTES, 'A text search view must hold the longest text a symbol may have.');\n\n if (area.length <= reach) {\n return (from) => area.indexOf(0, from);\n }\n\n let base = 0;\n let view = area.subarray(0, reach);\n\n return (from) => {\n if (from - base > rebaseAfter) {\n base = from;\n view = area.subarray(base, Math.min(area.length, base + reach));\n }\n\n const found = view.indexOf(0, from - base);\n\n return found === -1 ? -1 : base + found;\n };\n}\n\n/**\n * Where the text starting at `from` ends: the index of its NUL terminator.\n *\n * @param {(from: number) => number} findNul The field's `nulFinder`.\n * @param {number} areaEnd The byte after the field's last.\n * @param {number} from The first byte of the text.\n * @param {string} kind 'String symbol' or 'Dual string symbol', for the error.\n * @param {string} fieldName The field, for the error.\n * @param {string} filePath The file, for the error.\n * @param {number} base Where the buffer's first byte sits in the symbol table - see `parseFieldSymbols`.\n * @return {number} The index of the terminator.\n * @throws {QvdCorruptedError} If the text runs past the longest a symbol may hold, or has no terminator\n * before the end of the field's area.\n */\nfunction textEnd(findNul, areaEnd, from, kind, fieldName, filePath, base) {\n const found = findNul(from);\n\n if ((found === -1 ? areaEnd : found) - from > MAX_TEXT_BYTES) {\n throw new QvdCorruptedError(`${kind} exceeds maximum length`, {\n field: fieldName,\n maxLength: MAX_TEXT_BYTES,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n if (found === -1) {\n throw new QvdCorruptedError(`${kind} not null-terminated`, {\n field: fieldName,\n pointer: base + from,\n areaEnd: base + areaEnd,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return found;\n}\n\n/**\n * Refuses a number that would be read past the end of the field's area.\n *\n * @param {string} message What was being read.\n * @param {number} pointer The first byte of the number.\n * @param {number} areaEnd The byte after the field's last.\n * @param {string} fieldName The field, for the error.\n * @param {string} filePath The file, for the error.\n * @param {number} base Where the buffer's first byte sits in the symbol table - see `parseFieldSymbols`.\n * @return {never}\n * @throws {QvdCorruptedError} Always.\n */\nfunction overflow(message, pointer, areaEnd, fieldName, filePath, base) {\n throw new QvdCorruptedError(message, {\n field: fieldName,\n pointer: base + pointer,\n areaEnd: base + areaEnd,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n}\n\n/**\n * Decodes one field's symbols from the symbol table.\n *\n * Each symbol is a type byte - 1 int, 2 double, 4 string, 5 dual int, 6 dual double - then a 4-byte\n * int or 8-byte double, then a NUL-terminated UTF-8 text, as the type says. A symbol outside `keep` is\n * walked past without decoding, but its length still has to be found, and it is checked exactly as a\n * decoded one is, with the same error: a window changes which symbols are decoded, never whether damage\n * is found or what it is called. A number walked past used to be checked not at all.\n *\n * Every symbol has to end inside the field's own area, `start` to `end`, not merely inside the symbol\n * table. The next field's symbols start where this area ends, so a symbol allowed to run past it is read\n * partly from another field's bytes (#124): a text whose terminator was damaged took the next field's\n * first symbol as the rest of itself, and a number read its last bytes from there, with nothing thrown.\n * Held to the area, the walk ends exactly at `end`.\n *\n * Then the symbols walked have to be as many as the header's `NoOfSymbols` says. A terminator damaged in\n * the middle of the area merges two texts into one that still ends inside it, so the walk ends where it\n * should, one symbol short, and only the count shows it: every row pointing past the merged symbol read\n * its neighbour's value, and a read was refused only if it happened to decode a row pointing at the last\n * symbol, which no longer existed. Qlik and this library both write the count exactly, so any other\n * number is damage too, to the symbols or to the header.\n *\n * @param {Buffer} symbolBuffer The symbol table, or the range of it a read of some fields read.\n * @param {number} start The field's first byte in it.\n * @param {number} end The byte after the field's last, no further than the buffer's end.\n * @param {number} symbolCount How many symbols the header says the area holds: its `NoOfSymbols`.\n * @param {Set<number>|null} keep The symbols to decode, by index, or null for all of them.\n * @param {string} fieldName The field, for errors.\n * @param {string} filePath The file, for errors.\n * @param {{reach: number, rebaseAfter: number}} [search=TEXT_SEARCH] How far a terminator search may\n * reach. Only a test passes anything but the default.\n * @param {number} [base=0] Where `symbolBuffer` starts in the symbol table, added to every position an\n * error reports, so a read of one field's range names the bytes a read of the whole table would name.\n * @return {FieldSymbols} The field's symbols.\n * @throws {QvdCorruptedError} If a symbol runs past the end of the field's area, or the area holds a\n * different number of symbols from `symbolCount`.\n * @throws {QvdParseError} If a type byte is not one of the five.\n */\nexport function parseFieldSymbols(\n symbolBuffer,\n start,\n end,\n symbolCount,\n keep,\n fieldName,\n filePath,\n search = TEXT_SEARCH,\n base = 0,\n) {\n // The buffer up to the end of the field's area and no further, so a search for a terminator cannot find\n // one in the next field's bytes. A view, not a copy.\n //\n // Positions in it are positions in the buffer, which is the whole symbol table for a read of every field\n // and one range of it for a read of some. So an error reports `base` past what it walked, and a caller\n // reading one field of twenty is told the same bytes as a caller reading all twenty (#122).\n const area = symbolBuffer.subarray(0, end);\n const findNul = nulFinder(area, search);\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n let pointer = start;\n\n while (pointer < end) {\n const typeByte = area[pointer++];\n const decode = keep === null || keep.has(numbers.length);\n let number = null;\n let text = null;\n\n switch (typeByte) {\n case 1: {\n if (pointer + 4 > end) {\n overflow('Buffer overflow reading integer symbol', pointer, end, fieldName, filePath, base);\n }\n if (decode) {\n number = area.readInt32LE(pointer);\n }\n pointer += 4;\n break;\n }\n case 2: {\n if (pointer + 8 > end) {\n overflow('Buffer overflow reading double symbol', pointer, end, fieldName, filePath, base);\n }\n if (decode) {\n number = area.readDoubleLE(pointer);\n }\n pointer += 8;\n break;\n }\n case 4: {\n const terminator = textEnd(findNul, end, pointer, 'String symbol', fieldName, filePath, base);\n if (decode) {\n text = area.toString('utf8', pointer, terminator);\n }\n pointer = terminator + 1;\n break;\n }\n case 5:\n case 6: {\n const numberBytes = typeByte === 5 ? 4 : 8;\n if (pointer + numberBytes > end) {\n const read = typeByte === 5 ? 'dual integer symbol' : 'dual double symbol';\n overflow(`Buffer overflow reading ${read}`, pointer, end, fieldName, filePath, base);\n }\n\n const terminator = textEnd(\n findNul,\n end,\n pointer + numberBytes,\n 'Dual string symbol',\n fieldName,\n filePath,\n base,\n );\n if (decode) {\n number = typeByte === 5 ? area.readInt32LE(pointer) : area.readDoubleLE(pointer);\n text = area.toString('utf8', pointer + numberBytes, terminator);\n }\n pointer = terminator + 1;\n break;\n }\n default: {\n throw new QvdParseError('Unknown symbol type byte', {\n typeByte: typeByte.toString(16),\n offset: base + pointer - 1,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n }\n\n numbers.push(number);\n texts.push(text);\n }\n\n // Every read above is held to `end`, so the walk cannot stop anywhere else. Asserted rather than left\n // implicit, because a check relaxed later would let the last symbol run on into the next field's bytes\n // again, and nothing downstream would notice.\n assert(pointer === end, `The symbols of ${fieldName} were walked to byte ${pointer} of an area ending at ${end}.`);\n\n if (numbers.length !== symbolCount) {\n throw new QvdCorruptedError('Symbol count mismatch', {\n field: fieldName,\n symbolCount: numbers.length,\n noOfSymbols: symbolCount,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return {numbers, texts};\n}\n\n/** A keep set that holds nothing, so `parseFieldSymbols` walks every symbol and decodes none. */\nconst DECODE_NOTHING = new Set();\n\n/**\n * How many symbols a field's area holds: the length `parseFieldSymbols` gives its arrays.\n *\n * It is that function told to decode nothing, not a second walk written beside it. The two-pass read\n * uses the count to decide which indices can address a symbol before any symbol is parsed. A count\n * that fell short of the parse by one would leave out a symbol some row needs, and that row would read\n * back `undefined` with nothing thrown, so the count has to come from the same loop. Walking costs each\n * symbol's length check and, for a text, the search for its terminator. The arrays it builds hold\n * nulls and are dropped at once.\n *\n * Being the same loop, it makes the same checks, `symbolCount` included, and refuses a field with the\n * error the parse would give. So what it returns is always `symbolCount`, and yet it is walked rather\n * than taken from the header: until the walk has checked it, the header's number is only what the file\n * claims, and one too large, damaged or not, bounds nothing. The count exists to bound the two-pass\n * read's set of indices on exactly such a file.\n *\n * @param {Buffer} symbolBuffer The whole symbol table.\n * @param {number} start The field's first byte in it.\n * @param {number} end The byte after the field's last, no further than the table's end.\n * @param {number} symbolCount How many symbols the header says the area holds: its `NoOfSymbols`.\n * @param {string} fieldName The field, for errors.\n * @param {string} filePath The file, for errors.\n * @return {number} The field's symbols.\n * @throws {QvdCorruptedError} If a symbol runs past the end of the field's area, or the area holds a\n * different number of symbols from `symbolCount`.\n * @throws {QvdParseError} If a type byte is not one of the five.\n */\nexport function countFieldSymbols(symbolBuffer, start, end, symbolCount, fieldName, filePath, base = 0) {\n return parseFieldSymbols(symbolBuffer, start, end, symbolCount, DECODE_NOTHING, fieldName, filePath, undefined, base)\n .numbers.length;\n}\n","// @ts-check\n\nimport {dualFromSymbol} from '../QvdDual.js';\nimport {isNumericText} from './cellRules.js';\n\n/**\n * @typedef {import('./storedSymbols.js').StoredSymbolsEntry} StoredSymbolsEntry\n */\n\n/**\n * Both halves of each symbol of a field, aligned with its symbols: the text, or null for a pure\n * number, and the number, or null for a pure string.\n *\n * What a columnar read keeps for a field whose cells do not show every half, so a column can answer\n * `textAt` and give a date read as text its serial.\n *\n * @typedef {Object} SymbolHalves\n * @property {ReadonlyArray<string|null>} texts Each symbol's text.\n * @property {ReadonlyArray<number|null>} numbers Each symbol's number.\n */\n\n/**\n * What one field's symbols read as, and what has to be kept so they write back as the same symbols.\n *\n * Runs once per symbol, not once per cell: every row holding a symbol shares the value resolved here.\n *\n * A symbol reads as follows, the representation depending only on its type and the options - never on\n * the other symbols of the field, and never on the window:\n *\n * | Symbol | `'number'` (default) | `'text'` | `'both'` |\n * | --- | --- | --- | --- |\n * | int, double | the number | the number | the number |\n * | string | the string | the string | the string |\n * | string, numeric text, `coerce` on | `Number(text)` | `Number(text)` | `Number(text)` |\n * | dual | its number | its text | a frozen `QvdDual` |\n * | dual, numeric text, `coerce` on | its number | its number | a frozen `QvdDual` |\n * | NULL | null | null | null |\n *\n * A numeric text is one `isNumericText` accepts. `coerce` reaches only a cell that would otherwise be a\n * string: a string symbol in every mode, and a dual under `'text'`. A dual's numeric text reads as the\n * number Qlik *stored*, not as `Number(text)`, so a dual's number is the same in every mode that shows it.\n * The two need not be close. A text that spells the number can still parse to the double beside it -\n * Qlik stores 1.1400000000000001 for `1.14` - and a text that shows it rounded, or shows another value\n * such as a date as `20160113`, parses to a different number altogether.\n *\n * Wherever a cell shows only one half, the symbol is recorded, keyed by the value the cell holds, in\n * symbol order - which for a Qlik file is the order values first appear. That is pass A. Pass B runs\n * only for a field in which pass A recorded something and which also holds pure symbols: a pure\n * symbol that reads as a value already recorded is recorded too, so the writer can see that the value\n * stands for two different symbols and refuse it, rather than silently writing both as one. A Qlik\n * file keeps one symbol per value in a field, so for one pass B finds nothing to add.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols, both halves null where\n * the two-pass path did not decode one.\n * @param {string} field The field name, for the record.\n * @param {'number'|'text'|'both'} mode The `duals` option.\n * @param {boolean} coerce Whether a numeric text reads as a number.\n * @param {boolean} wantHalves Whether to return both halves of every symbol, for a columnar read.\n * @return {{values: Array<any>, entry: StoredSymbolsEntry|null, halves: SymbolHalves|null}} The value of\n * each symbol - undefined where it was filtered out - the field's record entry, or null when every\n * cell shows its whole symbol, and the halves when asked for and the field has a symbol whose cell\n * does not show both.\n */\nexport function resolveFieldSymbols(symbols, field, mode, coerce, wantHalves) {\n const length = symbols.numbers.length;\n const values = new Array(length);\n\n // Pass A's entries, in symbol order. Pushed as they are found rather than marked and collected,\n // because a field read from a Qlik file never needs pass B to add anything.\n /** @type {Array<number|string>} */\n const entryValues = [];\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n let pure = 0;\n let partial = false;\n\n for (let index = 0; index < length; index++) {\n const text = symbols.texts[index];\n const number = symbols.numbers[index];\n\n if (text === null) {\n // Neither half: a symbol the two-pass path did not decode, which no row of the window uses.\n values[index] = number === null ? undefined : number;\n if (number !== null) pure++;\n continue;\n }\n\n if (number === null) {\n if (coerce && isNumericText(text)) {\n values[index] = Number(text);\n entryValues.push(values[index]);\n numbers.push(null);\n texts.push(text);\n partial = true;\n } else {\n values[index] = text;\n pure++;\n }\n\n continue;\n }\n\n partial = true;\n\n if (mode === 'both') {\n // One frozen QvdDual per symbol, shared by every row holding it. Only this mode builds one; the\n // parser never does.\n values[index] = dualFromSymbol(number, text);\n continue;\n }\n\n values[index] = mode === 'number' || (coerce && isNumericText(text)) ? number : text;\n entryValues.push(values[index]);\n numbers.push(number);\n texts.push(text);\n }\n\n /** @type {StoredSymbolsEntry|null} */\n let entry = null;\n\n if (entryValues.length > 0) {\n entry =\n pure > 0 && collides(symbols, values, new Set(entryValues))\n ? collisionEntry(symbols, field, values, mode)\n : Object.freeze({\n field,\n values: Object.freeze(entryValues),\n numbers: Object.freeze(numbers),\n texts: Object.freeze(texts),\n });\n }\n\n return {values, entry, halves: wantHalves && partial ? symbolHalves(symbols) : null};\n}\n\n/**\n * Whether a pure symbol reads as a value pass A recorded - pass B's question.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {Array<any>} values What each symbol reads as.\n * @param {Set<any>} recorded The values pass A recorded. A Set compares by SameValueZero, the same\n * equality the writer's Map uses to look a cell up.\n * @return {boolean} True when one does.\n */\nfunction collides(symbols, values, recorded) {\n for (let index = 0; index < values.length; index++) {\n if (!isPure(symbols, index, values[index])) {\n continue;\n }\n\n if (recorded.has(values[index])) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether a symbol's cell shows the whole symbol: a pure number, or a pure string read as itself.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {number} index The symbol.\n * @param {any} value What it reads as.\n * @return {boolean} True for a pure symbol pass A did not record; false for one never decoded.\n */\nfunction isPure(symbols, index, value) {\n const text = symbols.texts[index];\n const number = symbols.numbers[index];\n\n return text === null ? number !== null : number === null && value === text;\n}\n\n/**\n * A field's record entry when pass B has something to add: pass A's symbols, and every pure symbol\n * that reads as one of their values, all in symbol order.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {string} field The field name.\n * @param {Array<any>} values What each symbol reads as.\n * @param {'number'|'text'|'both'} mode The `duals` option.\n * @return {StoredSymbolsEntry} The frozen entry.\n */\nfunction collisionEntry(symbols, field, values, mode) {\n const recorded = new Set();\n /** @type {Array<boolean>} */\n const inPassA = values.map((value, index) => {\n if ((symbols.numbers[index] === null && symbols.texts[index] === null) || isPure(symbols, index, value)) {\n return false;\n }\n\n // A dual read as a half, or a string coerced to a number. A 'both' dual is its own QvdDual cell.\n const recordedHere = !(mode === 'both' && symbols.texts[index] !== null && symbols.numbers[index] !== null);\n\n if (recordedHere) {\n recorded.add(values[index]);\n }\n\n return recordedHere;\n });\n\n /** @type {Array<number|string>} */\n const entryValues = [];\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n\n for (let index = 0; index < values.length; index++) {\n if (inPassA[index] || (isPure(symbols, index, values[index]) && recorded.has(values[index]))) {\n entryValues.push(values[index]);\n numbers.push(symbols.numbers[index]);\n texts.push(symbols.texts[index]);\n }\n }\n\n return Object.freeze({\n field,\n values: Object.freeze(entryValues),\n numbers: Object.freeze(numbers),\n texts: Object.freeze(texts),\n });\n}\n\n/**\n * Both halves of every symbol of a field: the decoded arrays themselves, frozen, since nothing else\n * holds them once the read resolves.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @return {SymbolHalves} The halves, null for a filtered-out symbol.\n */\nfunction symbolHalves(symbols) {\n return Object.freeze({texts: Object.freeze(symbols.texts), numbers: Object.freeze(symbols.numbers)});\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {asDual} from './util/cellRules.js';\nimport {readerOptionsFrom, windowFrom} from './util/readOptions.js';\n\n/**\n * @typedef {import('./util/resolveSymbols.js').SymbolHalves} SymbolHalves\n */\n\n/**\n * The number a symbol's value stands for, or NaN.\n *\n * A number is itself and a dual is its number. A string is NaN, unless the read kept its halves and\n * the symbol has a number - a dual read as its text, such as a date read with `{duals: 'text'}`, whose\n * serial is still the value Qlik sums and compares by.\n *\n * @param {any} value The symbol's value.\n * @param {number|null} number The symbol's stored number, from its halves, or null.\n * @return {number} The number.\n */\nfunction numberOf(value, number) {\n if (typeof value === 'number') {\n return value;\n }\n\n if (typeof value === 'string') {\n return number ?? NaN;\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.number === 'number' ? dual.number : NaN;\n}\n\n/**\n * The text a symbol's value stands for, derived from the value alone.\n *\n * @param {any} value The symbol's value.\n * @return {string|null} A string itself, a dual's text, or null.\n */\nfunction textOf(value) {\n if (typeof value === 'string') {\n return value;\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.text === 'string' ? dual.text : null;\n}\n\n/**\n * One column of a QVD, as the file stores it: a code per row and a dictionary of values.\n *\n * This is the shape the format already has. A QVD does not store a value per cell; it stores a\n * table of distinct symbols per field and an array of indices into it. Keeping that shape is\n * what makes a column cheap - four bytes per row, plus one entry per *distinct* value - and it\n * is why none of the questions that dog a per-row typed array arise here:\n *\n * - A mixed column needs no decision, because nothing per row is typed. On the bundled\n * `chicago_taxi_rides_2016_01` fixture, read with the default options, **exactly one of its 20\n * columns is strictly numeric** - `trip_start_timestamp`, whose timestamps read as numbers - and\n * two are 100% strings: `pickup_census_tract`, every cell of it blank, and `payment_type`.\n * `dropoff_census_tract` is 43.3% empty strings, and a `Float64Array` of values would put NaN in\n * all of those rows and erase Qlik's distinction between a blank and a number.\n * - NULL is a property of the position, not of the value: `codes[row] < 0`. No sentinel is\n * invented, so no sentinel can collide with real data.\n * - An all-null column, a single-valued column and a zero-row column are the same code path.\n */\nexport class QvdColumn {\n /**\n * @param {string} name The field name.\n * @param {Int32Array} codes One stored index per row, bias applied. Negative means NULL.\n * @param {Array<any>} symbols The field's distinct values, indexed by code.\n * @param {SymbolHalves|null} [halves=null] Both halves of each symbol, aligned with `symbols`, for a\n * field whose values do not show them all - a dual read as one half, a string read as a number.\n * Without them, the halves are derived from the values: a string is its own text, a dual has its\n * own, and a number has none.\n */\n constructor(name, codes, symbols, halves = null) {\n this._name = name;\n this._codes = codes;\n this._symbols = symbols;\n this._halves = halves;\n\n Object.freeze(this);\n }\n\n /** @return {string} The field name. */\n get name() {\n return this._name;\n }\n\n /** @return {number} Rows in the column. */\n get length() {\n return this._codes.length;\n }\n\n /**\n * The stored index of each row. Negative means NULL.\n *\n * The table's own array, not a copy - it is the thing that makes this cheap, and copying it\n * per call would defeat the point. Treat it as read-only.\n *\n * @return {Int32Array} One code per row.\n */\n get codes() {\n return this._codes;\n }\n\n /**\n * The field's distinct values, indexed by the codes.\n *\n * One entry per distinct value, not per row: a few thousand entries for a column of millions.\n *\n * A windowed read that filters the symbol table decodes only the symbols its rows use. Every other\n * entry is `undefined` - not `null`, which a QVD never stores as a symbol - and no code refers to it.\n *\n * @return {ReadonlyArray<any>} The dictionary.\n */\n get symbols() {\n return this._symbols;\n }\n\n /**\n * The value of one row.\n *\n * @param {number} row The row index.\n * @return {any} The value, or null where the file stores NULL.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n at(row) {\n if (!Number.isInteger(row) || row < 0 || row >= this._codes.length) {\n throw new QvdValidationError('Row index out of bounds', {\n column: this._name,\n row,\n length: this._codes.length,\n });\n }\n\n const code = this._codes[row];\n\n return code < 0 ? null : this._symbols[code];\n }\n\n /**\n * The text of one row: the text Qlik displays for its value.\n *\n * A string is its own text and a dual has its own. A value read as one half of a symbol - a date\n * read as its serial, a string read as a number - has the text the file stores for it, and a pure\n * number has none.\n *\n * @param {number} row The row index.\n * @return {string|null} The text, or null for NULL and for a number with no text.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n textAt(row) {\n if (!Number.isInteger(row) || row < 0 || row >= this._codes.length) {\n throw new QvdValidationError('Row index out of bounds', {\n column: this._name,\n row,\n length: this._codes.length,\n });\n }\n\n const code = this._codes[row];\n\n if (code < 0) {\n return null;\n }\n\n return this._halves !== null ? (this._halves.texts[code] ?? null) : textOf(this._symbols[code]);\n }\n\n /**\n * The text of each distinct value, indexed by the codes, as `textAt` gives it per row.\n *\n * @return {ReadonlyArray<string|null>} One text per symbol, null where a symbol has none.\n */\n symbolTexts() {\n if (this._halves !== null) {\n return this._halves.texts;\n }\n\n return Object.freeze(this._symbols.map(textOf));\n }\n\n /**\n * Iterates the column's values without materialising it.\n *\n * @return {Iterator<any>} An iterator over the values, NULLs included as null.\n */\n [Symbol.iterator]() {\n const codes = this._codes;\n const symbols = this._symbols;\n let row = 0;\n\n return {\n next() {\n if (row >= codes.length) {\n return {done: true, value: undefined};\n }\n\n const code = codes[row++];\n\n return {done: false, value: code < 0 ? null : symbols[code]};\n },\n };\n }\n\n /**\n * The column as a plain array of values, one per row.\n *\n * Lossless, and cell-for-cell what `QvdDataFrame.data[row][column]` would hold. The caller\n * owns the result; the table keeps no reference to it, so two calls return two arrays.\n *\n * @return {Array<any>} One value per row.\n */\n toArray() {\n const out = new Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n out[row] = code < 0 ? null : this._symbols[code];\n }\n\n return out;\n }\n\n /**\n * The dictionary as numbers, for scanning without materialising the column.\n *\n * One entry per *distinct* value, not per row - 17 KB for a column of 1.7 million rows with\n * 2,188 symbols - so this is the cheap conversion, where `toFloat64Array()` is the expensive\n * one. Non-numeric symbols become NaN, which is safe here in a way it is not per row: the\n * codes still distinguish NULL, and a caller that wants the blank back still has `symbols`.\n *\n * A dual is its number, however it was read: a `QvdDual` gives `.number`, and a date read with\n * `{duals: 'text'}` gives the serial the file stores for it, not NaN.\n *\n * Scanning `codes` against this is the fastest way to read a column, because both sides are\n * contiguous typed arrays and the dictionary fits in cache:\n *\n * ```js\n * const codes = column.codes;\n * const values = column.numericSymbols();\n * let total = 0;\n * for (let row = 0; row < codes.length; row++) {\n * const code = codes[row];\n * if (code >= 0) {\n * const value = values[code];\n * if (!Number.isNaN(value)) total += value;\n * }\n * }\n * ```\n *\n * @return {Float64Array} One number per distinct symbol, NaN where the symbol is not a number.\n */\n numericSymbols() {\n const out = new Float64Array(this._symbols.length);\n\n for (let index = 0; index < this._symbols.length; index++) {\n out[index] = numberOf(this._symbols[index], this._halves?.numbers[index] ?? null);\n }\n\n return out;\n }\n\n /**\n * The column as a `Float64Array`.\n *\n * Named for what it costs rather than offered as *the* representation, because it is lossy\n * and on real data it is lossy often: it cannot distinguish a blank from a number, and the\n * bundled taxi fixture has a column that is 43% blank. It therefore refuses by default\n * rather than quietly writing NaN over two fifths of a column.\n *\n * @param {Object} [options] Conversion options.\n * @param {'throw'|'nan'} [options.onNonNumeric='throw'] What to do with a value that is not a\n * number - including NULL. `'throw'` refuses and names the offending row; `'nan'` writes\n * NaN, which is the right choice only when the caller knows the column is numeric. A dual is a\n * number here, as it is to `numericSymbols`.\n * @return {Float64Array} One number per row.\n * @throws {QvdValidationError} If a value is not a number and `onNonNumeric` is `'throw'`.\n */\n toFloat64Array(options = {}) {\n const {onNonNumeric = 'throw'} = options;\n\n if (onNonNumeric !== 'throw' && onNonNumeric !== 'nan') {\n throw new QvdValidationError('onNonNumeric must be \"throw\" or \"nan\"', {\n column: this._name,\n provided: onNonNumeric,\n });\n }\n\n const out = new Float64Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n const value = code < 0 ? null : this._symbols[code];\n\n if (typeof value === 'number') {\n out[row] = value;\n continue;\n }\n\n // A dual's number, from the value or from the halves the read kept. NULL has neither.\n const number = value === null ? NaN : numberOf(value, this._halves?.numbers[code] ?? null);\n\n if (!Number.isNaN(number)) {\n out[row] = number;\n continue;\n }\n\n if (onNonNumeric === 'throw') {\n throw new QvdValidationError('Column holds a value that is not a number', {\n column: this._name,\n row,\n value,\n type: value === null ? 'null' : typeof value,\n hint: 'Pass {onNonNumeric: \"nan\"} to write NaN instead, or use toArray() to keep the value.',\n });\n }\n\n out[row] = NaN;\n }\n\n return out;\n }\n}\n\n/**\n * A QVD read as columns rather than as rows.\n *\n * The same file, the same decoder and the same symbol resolution as `QvdDataFrame.fromQvd` -\n * it simply stops before building rows, and keeps what the decoder already produced. Measured\n * on `__tests__/data/chicago_taxi_rides/chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows x 20\n * columns, as `heapUsed + arrayBuffers` either side of a forced collection with each read in a\n * process of its own - `benchmarks/capture-baseline.js`, on 1.0.1:\n *\n * | | retained | of it on the V8 heap | bytes/cell |\n * | --- | --- | --- | --- |\n * | `QvdDataFrame.fromQvd()` | 352 MiB | 352 MiB | 10.83 |\n * | `QvdColumnTable.fromQvd()` | 133 MiB | 3 MiB | 4.08 |\n *\n * Nearly all of a columnar read is its codes, an `Int32Array` per field, whose storage lives\n * outside the V8 heap - which is why the heap alone once put it at a fraction of this.\n *\n * It is not a data frame and does not become one. Offering a conversion would let a caller hold\n * both representations at once, which is the one configuration in which this costs more than it\n * saves. Re-reading a file as rows costs what reading it as rows always cost; there is no\n * saving to protect by avoiding that.\n */\nexport class QvdColumnTable {\n /**\n * @param {Object} decoded What the reader decoded.\n * @param {Array<string>} decoded.columns Field names, in file order.\n * @param {Array<Int32Array>} decoded.codesByField One code array per field.\n * @param {Array<Array<any>>} decoded.symbolsByField One dictionary per field.\n * @param {Array<SymbolHalves|null>} [decoded.halvesByField] Both halves of each symbol, per field,\n * or null for a field whose values show them.\n * @param {number} decoded.rowCount Rows decoded.\n * @param {any} decoded.metadata The raw QvdTableHeader.\n * @param {import('./util/storedSymbols.js').StoredSymbols|null} [decoded.storedSymbols] The\n * stored-symbol record, as a data frame of the same read carries it.\n * @param {any} decoded.loadStats Statistics about the read.\n */\n constructor({columns, codesByField, symbolsByField, halvesByField, rowCount, metadata, storedSymbols, loadStats}) {\n this._columns = columns;\n this._codesByField = codesByField;\n this._symbolsByField = symbolsByField;\n this._halvesByField = halvesByField ?? null;\n this._rowCount = rowCount;\n this._metadata = metadata;\n this._storedSymbols = storedSymbols ?? null;\n this._loadStats = loadStats;\n }\n\n /**\n * Reads a QVD file as columns.\n *\n * Takes the same options as `QvdDataFrame.fromQvd`, with the same meanings - one option\n * vocabulary for both read paths, because they are two answers about the same file rather than\n * two features. `{offset, limit}` is how a caller pages through a file columnwise; there is no\n * columnar `iterate()` because there is nothing for it to bound - a columnar read materialises\n * no rows, which is the memory chunking exists to cap.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Loading options, with the same meanings they have on `fromQvd`.\n * @param {number|null} [options.maxRows] Rows to decode. The older name for `limit`.\n * @param {number|null} [options.limit] Rows to decode, counting from `offset`.\n * @param {number} [options.offset] File row to start at.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear. Unselected fields have their symbols skipped entirely.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol's value is: its\n * number, its text, or a frozen `QvdDual` holding both. Whichever it is, `column.textAt` gives the\n * text and `numericSymbols` the number. Anything else throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a value that would be a string is a\n * number when its text is not blank and `Number(text)` is finite - a string symbol as\n * `Number(text)`, a dual read as text as its stored number. `column.textAt` still gives the text.\n * Anything but a boolean throws.\n * @param {Function} [options.onProgress] Progress callback, `{stage, current, total, percent}`.\n * @param {AbortSignal} [options.signal] Cancels the read.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor] Fraction of the memory budget a load may use.\n * @param {number} [options.symbolFilteringThreshold] Symbol table size above which a limited\n * read switches to two-pass filtering.\n * @return {Promise<QvdColumnTable>} The file, as columns.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n const reader = new QvdFileReader(path, {\n ...readerOptionsFrom(options),\n\n // This read builds no rows, so the memory guard must not charge it for them. A columnar\n // read of the 38MB taxi fixture completes in a 15MB heap; charged the row cost it was\n // refused below a 2GB one.\n materialisesRows: false,\n });\n\n return await reader.loadColumnar(windowFrom(options));\n }\n\n /** @return {Array<string>} Field names, in file order. */\n get columns() {\n return this._columns;\n }\n\n /** @return {number} Rows decoded. */\n get rowCount() {\n return this._rowCount;\n }\n\n /** @return {Array<number>} `[rows, columns]`, as on a data frame. */\n get shape() {\n return [this._rowCount, this._columns.length];\n }\n\n /** @return {any} The raw `QvdTableHeader`. */\n get metadata() {\n return this._metadata;\n }\n\n /** @return {any} Statistics about the read. */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * The stored-symbol record of the read, as `QvdDataFrame.storedSymbols` describes it.\n *\n * @return {import('./util/storedSymbols.js').StoredSymbols|null} The record, or null.\n */\n get storedSymbols() {\n return this._storedSymbols;\n }\n\n /**\n * One column.\n *\n * @param {string} name The field name.\n * @return {QvdColumn} The column.\n * @throws {QvdValidationError} If the field is not in this file.\n */\n column(name) {\n const index = this._columns.indexOf(name);\n\n if (index === -1) {\n throw new QvdValidationError(`Column '${name}' does not exist`, {\n column: name,\n availableColumns: this._columns,\n });\n }\n\n return new QvdColumn(\n name,\n this._codesByField[index],\n this._symbolsByField[index],\n this._halvesByField?.[index] ?? null,\n );\n }\n}\n","// @ts-check\n\nimport xml from 'xml2js';\n// Node's assert, used only for invariants a bug in this library would violate - \"this private\n// method ran after the one that fills the field it reads\". Never for input: everything a caller\n// can get wrong throws a QvdError with a context object instead.\n//\n// #143 read the old Copilot instruction \"use assertions for validation\" as an explanation for\n// these calls. It is not: every one sits after a method that either assigns the field\n// unconditionally or throws, and 3,570 corruption cases across every bundled fixture and every\n// entry point produced no AssertionError. They are checked, and they stay.\nimport assert from 'assert';\nimport {QvdDataFrame} from './QvdDataFrame.js';\nimport {QvdParseError, QvdValidationError, QvdCorruptedError} from './QvdErrors.js';\nimport {checkPath} from './util/validatePath.js';\nimport {openChecked} from './util/openChecked.js';\nimport {closeAfter, rethrowAsIoError} from './util/ioErrors.js';\nimport {decodeIndexColumn} from './util/bitUtils.js';\nimport {checkMemory, getMemoryBudget, validateMemoryAvailability, warnLargeSymbolTable} from './util/memoryUtils.js';\nimport {\n headerInteger,\n validateBitFields,\n validateHeaderStructure,\n validateSymbolAreas,\n validateSymbolTableSize,\n validateSymbolTableSizeEarly,\n validateFieldMetadata,\n validateIndexTableMetadata,\n validateFieldBitMetadata,\n validateRecordCount,\n validateRecordSize,\n} from './util/validationUtils.js';\nimport {countFieldSymbols, parseFieldSymbols} from './util/symbolParser.js';\nimport {\n normaliseCoerceNumericStrings,\n normaliseDuals,\n normaliseWindow,\n resolveWindow,\n selectFields,\n requireChunkSize,\n} from './util/readOptions.js';\nimport {resolveFieldSymbols} from './util/resolveSymbols.js';\nimport {attachStoredSymbols, trustStoredSymbols} from './util/storedSymbols.js';\n\n/**\n * @typedef {import('./util/readOptions.js').QvdRowWindow} QvdRowWindow\n */\n\n/**\n * Maximum number of bytes searched for the XML header delimiter before giving up.\n * Real QVD headers are a few kilobytes; the largest observed is well under 100KB.\n */\nconst MAX_HEADER_SIZE = 16 * 1024 * 1024;\n\n/**\n * Maximum length of a single fs.read call. Node's fs.read binding requires the length to fit\n * in an Int32: a larger value aborts the process via a C++ assertion instead of throwing.\n */\nconst READ_CHUNK_SIZE = 512 * 1024 * 1024;\n\n/**\n * Rows the two-pass symbol analysis decodes at a time.\n *\n * The pass collects the *set* of stored indices a window references, and a set is the same\n * whether it is built in one pass or in slices - so this bounds the scratch column at 256KB\n * instead of four bytes per row of the window. It is a working-set size, not a correctness\n * parameter: any value gives the same answer.\n */\nconst ANALYSIS_SLICE_ROWS = 65536;\n\n/**\n * Bytes of records read from the file at a time.\n *\n * The index table is read in slices of whole records, into one buffer reused for every slice, and each\n * slice is decoded before the next is read. A read used to hold the file in one buffer - the whole of it,\n * or the header, the symbol table and every record of the window - so what it needed grew with the file:\n * `iterate()` over 2.24 GB held 2.24 GB from its first chunk on (#122). A slice bounds that at this size,\n * whatever the file's, and is large enough that the number of reads it takes costs nothing next to\n * decoding them. A record is at most 1 MB, so a slice always holds at least sixteen.\n *\n * The default of the reader's `sliceBytes` option, which only a test changes.\n */\nconst SLICE_BYTES = 16 * 1024 * 1024;\n\n/**\n * Distinct indices the symbol-usage pass keeps for one field before it counts the field's symbols.\n *\n * Below this it trusts the bound the field's bytes give, which costs nothing. Past it the set is large\n * enough to matter, and that bound says too little: a field holding one 50 MB string still allows 25\n * million. So the field's symbols are counted, one walk of its area, and the set is held to them. A\n * valid read that needs more than this many of one field's symbols pays that walk once. One that needs\n * fewer, which is what the two-pass path is for, never does.\n */\nconst COUNT_SYMBOLS_PAST = 65536;\n\n/**\n * Reads a file from its start, a chunk at a time, through a handle already open.\n *\n * The header used to be scanned with `fs.createReadStream(path)`, which opened the file a second time\n * by name - and the body was read by a third open, of the same name. Each was another resolution of\n * a path that can change between them: #247 was a symlink swapped in after the containment check, and\n * every one of those opens followed it. Reading the header through the one handle the read holds keeps\n * the header, the symbol table and the index table in the same file, and that file the one the check\n * approved.\n *\n * Positional reads, so the handle's own file position never moves and a later `readFile()` on it\n * still starts at the beginning. A read can return fewer bytes than it was asked for, and the chunk\n * is then shorter; nothing downstream assumes a size.\n *\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {number} chunkSize The most to read at a time.\n * @param {(error: unknown) => never} failed The read's `rethrowAsIoError` handler.\n * @yield {Buffer} The file's bytes, in order, until its end.\n */\nasync function* chunksFrom(handle, chunkSize, failed) {\n let position = 0;\n\n for (;;) {\n const buffer = Buffer.alloc(chunkSize);\n const {bytesRead} = await handle.read(buffer, 0, chunkSize, position).catch(failed);\n\n if (bytesRead === 0) {\n return;\n }\n\n // What arrived, copied when it is short, so a short last chunk does not pin a whole chunk's buffer.\n yield bytesRead === chunkSize ? buffer : Buffer.from(buffer.subarray(0, bytesRead));\n position += bytesRead;\n }\n}\n\n/**\n * Parses a QVD's XML header, reporting a header that is not XML as a `QvdParseError`.\n *\n * xml2js rejects malformed XML with its SAX parser's bare `Error` - \"Unexpected close tag\", \"Non-whitespace\n * before first tag.\" - which names neither the file nor what was being read, and which escapes every\n * `catch (error) { if (error instanceof QvdError) ... }` a caller has written around a read. It is where\n * most damage to a header ends up: 75 of 120 random byte flips inside one, in the September 2026 audit.\n * Both places that parse a header go through this, so the two cannot report the same header differently.\n *\n * Well-formed XML that is not a QVD header parses, and is `validateHeaderStructure`'s to refuse.\n *\n * Note: xml2js (via sax-js) does not support external entity resolution by default, providing inherent\n * protection against XXE attacks.\n *\n * @param {string} text The header, delimiter included.\n * @param {string} file The file, for the error.\n * @param {string} stage Stage name recorded in the error context.\n * @return {Promise<any>} The parsed header.\n * @throws {QvdParseError} If the text is not well-formed XML, or parses to nothing.\n */\nasync function parseHeaderXml(text, file, stage) {\n let parsed;\n\n try {\n parsed = await xml.parseStringPromise(text, {explicitArray: false});\n } catch (error) {\n throw new QvdParseError(\n 'The XML header could not be parsed.',\n {\n // The first line of the parser's message. The rest is the line and column it stopped at, which\n // stay on `cause`.\n reason: String(/** @type {any} */ (error)?.message ?? error).split('\\n')[0],\n file,\n stage,\n },\n {cause: error},\n );\n }\n\n if (!parsed) {\n throw new QvdParseError('The XML header could not be parsed.', {file, stage});\n }\n\n return parsed;\n}\n\n/**\n * Parses a QVD file and loads it into memory.\n */\n/**\n * Bytes of symbols a read of these fields will read: their areas, not the table those areas sit in.\n *\n * A read of one field of a file whose other fields hold gigabytes reads that field's area alone, so\n * sizing it by the table refused reads that fit a hundred times over - the refusal #122 is about. The\n * whole table stands in where the header's areas cannot be used, or claim more than the table holds,\n * because then this is a guess and the guess should be the large one.\n *\n * Shared by the read and by the pre-flight check, so that what the check approves is what the read is\n * then measured against. Two copies of this arithmetic would be two answers about one file.\n *\n * @param {Array<any>} selected The fields the read selects, from the header.\n * @param {number} symbolTableLength The symbol table's declared length.\n * @return {number} Bytes.\n */\nfunction symbolBytesOf(selected, symbolTableLength) {\n const areaBytes = selected.map((/** @type {any} */ field) => headerInteger(field['Length']));\n\n return areaBytes.every((bytes) => Number.isSafeInteger(bytes) && bytes >= 0)\n ? Math.min(\n symbolTableLength,\n areaBytes.reduce((sum, bytes) => sum + bytes, 0),\n )\n : symbolTableLength;\n}\n\n/**\n * How many times a read passes over the records it covers.\n *\n * Two where the symbol-usage pass is still ahead of it: that pass reads the window's records to find\n * which symbols its rows use, and the decode then reads them again. One otherwise. It is the read's\n * I/O rather than its memory - the records go through one buffer either way - and it is reported so\n * that `estimate.readBytes` describes the file access a read really makes.\n *\n * @param {boolean} analysisAhead Whether the symbol-usage pass has still to run.\n * @return {number} Passes over the records.\n */\nfunction readPasses(analysisAhead) {\n return analysisAhead ? 2 : 1;\n}\n\n/**\n * Refuses an `onProgress` or `signal` that is not one, in the vocabulary the options use.\n *\n * Shared because the pair arrives by two doors: the constructor, for a reader built for one read, and\n * `observeNextRead`, for a `QvdFile` page that watches its own. One set of rules, so a page cannot be\n * watched by something a read would have refused.\n *\n * @param {any} onProgress The progress callback, or undefined.\n * @param {any} signal The abort signal, or undefined.\n * @param {string} path The file, for the error.\n * @return {void}\n * @throws {QvdValidationError} If either is present and not of its type.\n */\nfunction validateWatchers(onProgress, signal, path) {\n if (onProgress !== undefined && typeof onProgress !== 'function') {\n throw new QvdValidationError('onProgress must be a function', {\n provided: onProgress,\n type: typeof onProgress,\n reason: 'option',\n option: 'onProgress',\n file: path,\n });\n }\n\n // Checked here rather than at the first use, so a caller who passes something signal-shaped finds out\n // before the file is opened instead of discovering that cancellation silently did nothing.\n // `throwIfAborted` is the whole contract this reader needs from it.\n if (signal !== undefined && (typeof signal !== 'object' || signal === null || typeof signal.aborted !== 'boolean')) {\n throw new QvdValidationError('signal must be an AbortSignal', {\n provided: signal,\n type: typeof signal,\n reason: 'option',\n option: 'signal',\n file: path,\n });\n }\n}\n\nexport class QvdFileReader {\n /**\n * Constructs a new QVD file parser.\n *\n * @param {string} filePath The path to the QVD file to load.\n * @param {Object} [options={}] Options for the reader.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction (0.0-1.0) of the memory budget a\n * load may use. The budget is the smaller of the V8 heap limit and any container memory limit;\n * what the OS reports as available is recorded for diagnostics and deliberately not allowed to\n * bind - see `getMemoryBudget`. Default is 0.8. **Zero disables the memory\n * check entirely**, which is the escape hatch for runtimes whose limits cannot be measured -\n * Bun reports its current heap as its heap limit - and for callers who would rather manage\n * memory themselves than trust the estimate.\n * @param {boolean} [options.materialisesRows=true] Whether this read will build row arrays.\n * False for a columnar read, whose memory is TypedArray backing stores outside the V8 heap\n * and which must not be charged the row cost.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes,\n * above which a lazy load switches to the two-pass filtering path. The default of 50MB is\n * the point where the extra analysis pass pays for itself; lower it to use filtering on\n * smaller files, raise it to keep the simpler single-pass read for longer.\n * @param {number} [options.sliceBytes=16777216] The most bytes of records a read holds at a time. An\n * option rather than a constant for the reason `symbolFilteringThreshold` is one: so that a test can\n * cross the boundaries between slices in a small file. There is no other reason to change it, and it\n * is not one of the options a read through `QvdDataFrame` or `QvdColumnTable` passes on.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear. Null reads every field, in file order. An unknown or repeated name is refused.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol - a number with the\n * text Qlik displays for it, such as a date - reads as. `'number'` gives its number, which is the\n * value Qlik sums, sorts and compares by; `'text'` gives its text; `'both'` gives a frozen\n * `QvdDual` holding both halves, shared by every row that holds the symbol. Under `'number'` and\n * `'text'` the half a cell does not show is kept in the frame's `storedSymbols`, so a write stores\n * the dual again. An int, a double, a string and NULL read the same in every mode. Any other value\n * throws a `QvdValidationError`.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite: a string symbol in\n * every `duals` mode, as `Number(text)`, and a dual's text under `duals: 'text'`, as the number the\n * dual stores. The text is kept in the frame's `storedSymbols`, so a write stores the string or the\n * dual again. Anything but a boolean, `undefined` or null throws a `QvdValidationError`.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}` as the\n * read proceeds - the same shape `QvdFileWriter` emits.\n * @param {AbortSignal} [options.signal] Cancels the read. When it is aborted the read throws\n * `signal.reason`, exactly as `signal.throwIfAborted()` does.\n */\n constructor(filePath, options = {}) {\n const {\n allowedDir,\n memorySafetyFactor = 0.8,\n symbolFilteringThreshold = 50 * 1024 * 1024,\n sliceBytes = SLICE_BYTES,\n materialisesRows = true,\n fields = null,\n duals,\n coerceNumericStrings,\n onProgress,\n signal,\n } = options;\n this._materialisesRows = materialisesRows;\n const checked = checkPath(filePath, allowedDir);\n this._path = checked.path;\n /**\n * The allowed directory, resolved. Kept because the path is checked again immediately before it is\n * opened - see `_readData` - and that check has to be made against the directory this one was,\n * whatever the working directory has become since.\n */\n this._allowedDir = checked.base;\n /** What a dual symbol reads as. Checked here, so a bad value fails before the file is opened. */\n this._duals = normaliseDuals(duals, this._path);\n /**\n * Whether a cell that would be a string reads as a number when its text is a finite number. Off\n * unless asked for; on, the text is recorded in the frame's `storedSymbols`, so a write stores the\n * string or the dual it was read from. Checked here, like `duals`, before the file is opened.\n */\n this._coerceNumericStrings = normaliseCoerceNumericStrings(coerceNumericStrings, this._path);\n this._memorySafetyFactor = memorySafetyFactor;\n this._symbolFilteringThreshold = symbolFilteringThreshold;\n\n if (!Number.isSafeInteger(sliceBytes) || sliceBytes <= 0) {\n throw new QvdValidationError('sliceBytes must be a positive integer', {\n provided: sliceBytes,\n type: typeof sliceBytes,\n file: this._path,\n });\n }\n\n /** The most bytes of records a read holds at a time - see `_forEachSlice`. */\n this._sliceBytes = sliceBytes;\n\n validateWatchers(onProgress, signal, this._path);\n\n /** @type {Array<string>|null} */\n this._requestedFields = fields === undefined ? null : fields;\n this._onProgress = onProgress;\n this._signal = signal;\n\n /**\n * The XML header, delimiter included. The rest of the file is never held whole: the symbol table and\n * the records are read from `_handle` as they are parsed.\n *\n * @type {Buffer|null}\n */\n this._headerBuffer = null;\n /**\n * The file, open for as long as a read of rows needs it - from its header to its last record, or for\n * `iterateRows` to its last chunk - and closed by `_closeFile`. Null between reads.\n *\n * @type {import('fs/promises').FileHandle|null}\n */\n this._handle = null;\n /** The open read's `rethrowAsIoError` handler. @type {((error: unknown) => never)|null} */\n this._failed = null;\n /**\n * Whether a read is under way on this reader, from its first line to the close of its file. See\n * `_startRead`.\n */\n this._reading = false;\n /**\n * Where the selected fields' symbols are, and the bytes of those read so far: one entry per range of the\n * symbol table this read reads, dropped as each is parsed, or when the read ends before that. Null\n * between reads, and until the header says where the areas are. See `_symbolAreaPlan`.\n *\n * @type {{ranges: Array<{start: number, end: number, fields: number, buffer: Buffer|null}>,\n * byField: Map<any, {range: any, start: number, end: number}>}|null}\n */\n this._symbolAreas = null;\n\n /**\n * Fields this reader has decoded, by name, when it is paging - see `beginPaging`.\n *\n * Null unless a caller asked for it, because it is the one piece of reader state that deliberately\n * outlives a read. A `QvdFile` turns it on: its pages are reads of one file whose symbols do not\n * change between them, and decoding them is 72% of a page.\n */\n this._symbolCache = null;\n\n /**\n * The header the cache was decoded from, so that a file replaced at the same path between pages is\n * not answered from the old one's values.\n */\n this._cachedFor = null;\n this._headerOffset = null;\n this._symbolTableOffset = null;\n this._indexTableOffset = null;\n this._header = null;\n /**\n * Every field header in the file, in file order, and the caller's selection of them in the\n * order the result should carry. Both are set by `_parseHeader` and null until it has run.\n *\n * One derivation feeds the symbol table, the decoded columns and `columns`, which are three\n * arrays indexed by the same position. Deriving the selection separately at each of those\n * sites - which is what this replaced - meant three answers that had to agree by inspection\n * rather than by construction.\n *\n * @type {Array<any>|null}\n */\n this._allFields = null;\n /** @type {Array<any>|null} */\n this._selectedFields = null;\n /**\n * Whether every field's bit metadata has been validated. Header data, so it is checked once per\n * header: `_parseHeader` clears it whenever it reads one.\n */\n this._fieldBitMetadataValidated = false;\n /** @type {Array<import('./util/symbolParser.js').FieldSymbols>|null} Each selected field's decoded symbols. */\n this._symbolTable = null;\n /**\n * Stored symbol indices, one Int32Array per field rather than one array per row.\n *\n * Column-major because that is what lets the decoder hoist a field's bit offset, width and\n * bias out of the row loop and write straight into a typed array - no allocation per row or\n * per cell. Renamed from `_indexTable` deliberately: the shape changed, and a reader of this\n * code should not have to discover that from the subscripts.\n *\n * @type {Array<Int32Array>|null}\n */\n this._indexColumns = null;\n\n /** Rows actually decoded into `_indexColumns`. @type {number} */\n this._rowsDecoded = 0;\n /** @type {number|null} */\n this._fileSize = null;\n\n /** What the filesystem says this file is, for the cache's fingerprint. @type {string|null} */\n this._fileIdentity = null;\n /** Whether the header's declared extent fits inside the file. False until _readData says so. */\n this._headerMatchesFile = false;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * The same shape `QvdFileWriter._emitProgress` emits, deliberately: a caller who has written a\n * progress bar for a write should not have to write a second one for a read. The stage names\n * differ because the stages differ, but `symbol-table` and `index-table` mean the same thing on\n * both sides.\n *\n * @param {string} stage The current stage of the read.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n * @private\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n\n this._onProgress({stage, current, total, percent});\n }\n }\n\n /**\n * Throws if the caller has cancelled the read.\n *\n * Throws `signal.reason` - a `DOMException` named `AbortError` unless the caller aborted with a\n * reason of their own. That is what `AbortSignal` means everywhere else in Node, and inventing\n * a `QvdAbortError` here would make this library's cancellation the one a caller has to special\n * case.\n *\n * @private\n */\n _throwIfAborted() {\n if (this._signal) {\n this._signal.throwIfAborted();\n }\n }\n\n /**\n * Opens the file and reads its header, and for a read of rows checks that the read can be made.\n *\n * Nothing past the header is read here. The selected fields' symbols and the records are read by position\n * as they are parsed - see `_symbolAreaOf` and `_forEachSlice` - so no read holds the file in one buffer\n * (#122). A read of rows therefore leaves the file open, and whatever started the read closes it with\n * `_closeFile` once the last record it needs is decoded; a header-only read closes it here.\n *\n * A windowed read - anything with `offset`, `limit` or `maxRows` - reads the header, the symbols of the\n * fields it selects, and the window's records, and no byte between. Measured on\n * `chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows over 20 fields: the last thousand rows take 19 ms\n * against 636 ms for the whole file. A selected field's area is read in full whatever the window,\n * because a stored index in any row can address any of that field's symbols; the areas of the fields\n * `fields` leaves out are not read at all. So a window's gain scales with how much of the file is\n * rows: on a file whose bytes are mostly distinct values of the fields it reads there is very little\n * to save, which is what `symbolFilteringThreshold` and the two-pass path exist for.\n *\n * All of it goes through one handle, opened once, on the file the containment check approved. See\n * `chunksFrom` and `openChecked` for why a read no longer opens the path more than once.\n *\n * @param {QvdRowWindow} window The rows to read.\n * @param {boolean} [headerOnly=false] Stop once the XML header has been read, and close the file. This\n * is the metadata-only path: the header is a few kilobytes whatever the file's size, so reading a\n * schema costs the same for a 40MB file as for a 40GB one.\n * @param {{rows: number, perChunk: number}|null} [liveRows=null] Rows held at one instant when\n * that is fewer than the window covers - see `_prepare`.\n * @private\n */\n async _readData(window = {offset: 0, limit: null}, headerOnly = false, liveRows = null) {\n assert(this._reading, 'A read opens the QVD file only once it has started, through _startRead.');\n\n // A read begins by forgetting the one before it. A reader is reusable and the file at its path can have\n // changed, so a read that failed part-way used to leave the last successful read's symbols, codes and\n // row count on the reader, describing a file it was no longer reading. Cleared as the read starts\n // rather than when its file is closed, so that what a finished read parsed is still there to be looked\n // at - which is how the projection tests check that a read parsed one field and not every field.\n this._symbolTable = null;\n this._indexColumns = null;\n this._rowsDecoded = 0;\n\n this._throwIfAborted();\n this._emitProgress('read', 0, 1);\n\n // Every file-system call below goes through this, so a missing or unreadable file - or on Windows\n // one another process has locked - is a QvdIOError carrying the system code rather than Node's bare\n // error.\n const failed = rethrowAsIoError(this._path, 'read');\n\n // Checked again here, immediately before the open, rather than trusting the check the constructor\n // made: the open is held to what this check approved, and the nearer the two are the less there is\n // to hold. One open for the whole read, closed by `closeAfter` or `_closeFile`, so a close that fails\n // cannot replace the error the read is already throwing - a truncated file stays a QvdCorruptedError\n // rather than turning into a QvdIOError about the close - and is reported when the read succeeded.\n const handle = await openChecked(checkPath(this._path, this._allowedDir), 'read', failed);\n\n if (headerOnly) {\n await closeAfter(handle, failed, () => this._readFrom(handle, window, true, liveRows, failed));\n return;\n }\n\n this._handle = handle;\n this._failed = failed;\n\n try {\n await this._readFrom(handle, window, false, liveRows, failed);\n } catch (error) {\n await this._closeFile(true);\n throw error;\n }\n }\n\n /**\n * Starts a read on this reader, refusing it while another is under way.\n *\n * A read of rows holds the file, and what it has read of it, on the reader until it ends. A second read\n * started meanwhile - `load()` while an iteration is suspended, say - would take over that state and\n * leave the first read's file open. Reads one after another are fine. Called before a read takes charge\n * of closing the file, so that refusing the second read cannot close the first one's.\n *\n * The first thing every read does, and synchronous: the flag is set before the read's first `await`, so\n * two reads started together - `Promise.all([reader.load(), reader.load()])` - cannot both pass. The check\n * used to be of the handle, which is set only once the file has opened, and both did: the second read's\n * handle replaced the first's, which was never closed, and the first read to finish closed the file the\n * other was still reading.\n *\n * @throws {QvdValidationError} If a read is under way.\n * @private\n */\n _startRead() {\n if (this._reading) {\n throw new QvdValidationError('The reader is already reading this file: finish that read first', {\n file: this._path,\n });\n }\n\n this._reading = true;\n }\n\n /**\n * Ends the read `_startRead` began: closes its file, if it still holds one, and lets the next read start.\n *\n * @param {boolean} failing Whether the read is already throwing - see `_closeFile`.\n * @private\n */\n async _endRead(failing) {\n try {\n await this._closeFile(failing);\n } finally {\n this._reading = false;\n }\n }\n\n /**\n * Closes the file a read of rows opened, and drops what it had read of it.\n *\n * The rule `closeAfter` follows: a close that fails is reported only when the read succeeded, so it can\n * never replace the error that says what went wrong. After a successful read it is the only news.\n *\n * @param {boolean} failing Whether the read is already throwing.\n * @private\n */\n async _closeFile(failing) {\n const handle = this._handle;\n const failed = this._failed;\n\n this._handle = null;\n this._failed = null;\n this._symbolAreas = null;\n\n if (handle === null || failed === null) {\n return;\n }\n\n if (failing) {\n await handle.close().catch(() => {});\n return;\n }\n\n await handle.close().catch(failed);\n }\n\n /**\n * Runs a read, the only one under way on this reader, and closes its file when it ends, however it ends.\n *\n * @template T\n * @param {() => Promise<T>} read The read, from opening the file to its last record.\n * @return {Promise<T>} What it returned.\n * @private\n */\n async _closingAfter(read) {\n this._startRead();\n\n let result;\n\n try {\n result = await read();\n } catch (error) {\n await this._endRead(true);\n throw error;\n }\n\n await this._endRead(false);\n\n return result;\n }\n\n /**\n * Reads what `_readData` was asked for, through the handle it opened.\n *\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {QvdRowWindow} window The rows to read.\n * @param {boolean} headerOnly Stop once the XML header has been read.\n * @param {{rows: number, perChunk: number}|null} liveRows Rows held at one instant - see `_prepare`.\n * @param {(error: unknown) => never} failed The read's `rethrowAsIoError` handler.\n * @private\n */\n async _readFrom(handle, window, headerOnly, liveRows, failed) {\n // The header is scanned first on both paths, including a full load that is about to read the\n // whole file anyway. It costs a few kilobytes and it is what lets the memory check run\n // *before* the body is read: otherwise a 1.7GB file is loaded into memory in full and only\n // then refused, which is the opposite of what a safety check is for.\n const HEADER_DELIMITER = '\\r\\n\\0';\n const CHUNK_SIZE = 64 * 1024; // 64KB chunks - balance between memory and I/O efficiency\n\n /** @type {Array<Buffer>} */\n const headerChunks = [];\n let headerBytes = 0;\n /** Last (delimiter length - 1) bytes seen so far, carried across chunk boundaries. */\n let tail = Buffer.alloc(0);\n let headerDelimiterIndex = -1;\n\n // Read chunks until we find the delimiter.\n //\n // Chunks are collected and concatenated once, and each chunk is searched individually\n // (with a small carry-over so a delimiter straddling a chunk boundary is still found).\n // Concatenating the whole accumulated buffer on every chunk and re-scanning it from the\n // start is quadratic: a 200 MB delimiter-less file cost 43 s and 13 GB of memory.\n //\n // A failed read reaches the caller as a QvdIOError through `failed`, and anything else thrown here\n // - the corrupted-file error below, or a bug - passes through as it is. That is not an accident of\n // structure: the stream this used to be caught every error its iterator threw, and a version of\n // that catch once reported a bug with no `code` as a corrupt file.\n for await (const chunk of chunksFrom(handle, CHUNK_SIZE, failed)) {\n // Search the new chunk prefixed by the bytes already seen, so a delimiter spanning a\n // chunk boundary is not missed.\n //\n // The carry is kept in `tail` across iterations rather than read back off the previous\n // chunk, because a chunk may be shorter than the delimiter. Taking min(bytesSoFar, 2)\n // bytes from a 1-byte previous chunk yields only 1 byte, which both misses a delimiter\n // spread over three chunks and leaves the reported offset short by the difference.\n const chunkStart = headerBytes;\n const searchBuffer = tail.length > 0 ? Buffer.concat([tail, chunk]) : chunk;\n const foundInSearch = searchBuffer.indexOf(HEADER_DELIMITER);\n\n headerChunks.push(chunk);\n headerBytes += chunk.length;\n\n if (foundInSearch !== -1) {\n // searchBuffer starts tail.length bytes before this chunk does.\n headerDelimiterIndex = chunkStart - tail.length + foundInSearch;\n break;\n }\n\n // Copy the carry instead of keeping a subarray view, which would pin the whole chunk.\n tail = Buffer.from(searchBuffer.subarray(-(HEADER_DELIMITER.length - 1)));\n\n // Real QVD headers are a few kilobytes. Without a cap, a non-QVD or corrupt file is\n // read to its end before the error below is raised, which is a denial-of-service\n // vector for any service that accepts uploaded files.\n if (headerBytes > MAX_HEADER_SIZE) {\n throw new QvdCorruptedError(\n `The XML header delimiter was not found within the first ${MAX_HEADER_SIZE / (1024 * 1024)}MB of the file.`,\n {\n file: this._path,\n bytesSearched: headerBytes,\n maxHeaderSize: MAX_HEADER_SIZE,\n stage: 'readData',\n },\n );\n }\n }\n\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'readData',\n },\n );\n }\n\n const headerBuffer = Buffer.concat(headerChunks);\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n\n // Parse header to get metadata about symbol and index table locations\n const headerXml = headerBuffer.subarray(0, headerEndIndex).toString();\n const headerObj = await parseHeaderXml(headerXml, this._path, 'readData');\n const headerFields = validateHeaderStructure(headerObj, this._path, 'readData');\n\n const symbolTableOffset = headerEndIndex;\n const symbolTableLength = headerInteger(headerObj['QvdTableHeader']['Offset']);\n const indexTableOffset = symbolTableOffset + symbolTableLength;\n const recordSize = headerInteger(headerObj['QvdTableHeader']['RecordByteSize']);\n const totalRows = headerInteger(headerObj['QvdTableHeader']['NoOfRecords']);\n\n // The file's size bounds every read that follows, whatever the header says - and it is what says\n // whether the header describes this file at all. One `stat`, before the header-only return as well\n // as after it: `readMetadata` does not use the answer, but `checkRead` cannot do its job without\n // it, and a header-only read that skipped the call reported a truncated file as a read too large\n // to fit rather than as a file that is short.\n const {size: fileSize, ino, dev, mtimeMs} = await handle.stat().catch(failed);\n this._fileSize = fileSize;\n\n // What the file is, as the filesystem knows it, for the symbol cache to compare against - see\n // `_fileFingerprint`. The header's own numbers are not enough on their own: `QvdFileWriter` carries\n // `CreateUtcTime` over from the metadata it was given, so a read-modify-write that changes a text to\n // another of the same length rewrites every value while leaving every number this reader can see\n // identical. An atomic write renames a new file into place and changes the inode; an in-place one\n // (`{atomic: false}`) keeps it and moves `mtimeMs`.\n this._fileIdentity = `${dev}:${ino}:${mtimeMs}:${fileSize}`;\n\n // Decided again for this read, and cleared first: it describes the file being read now, and a reader\n // may read again - a file that has changed since, or another read of one that never matched. Left from\n // the read before, it said yes about a file whose numbers this one could not use, and\n // `_parseSymbolTable` gates its memory check on this flag alone. That check then estimated from a\n // `NaN` row count, which refuses nothing, so the structural error still came out of `_planIndexTable`:\n // wrong question, right answer. `_fieldBitMetadataValidated` is cleared per header for the same reason.\n this._headerMatchesFile = false;\n\n // Two conditions, and both exist so that a corrupt file keeps its accurate diagnosis instead of\n // being reported as an out-of-memory problem. The numbers have to be usable at all - a NaN or\n // negative Offset would produce a nonsense estimate - and they have to be consistent with the file\n // on disk. The estimate is computed from NoOfRecords, so a header that overstates it produces an\n // enormous figure: a truncated 3KB file claiming 900 million rows was refused for needing 530GB of\n // RAM, when what it actually needs is to be re-downloaded. Where the file contradicts its own\n // header, the memory check below stands aside and lets the structural checks say what is wrong.\n const headerNumbersUsable = [symbolTableLength, recordSize, totalRows].every(\n (value) => Number.isSafeInteger(value) && value >= 0,\n );\n\n if (headerNumbersUsable) {\n this._headerMatchesFile = headerEndIndex + symbolTableLength + totalRows * recordSize <= fileSize;\n }\n\n if (headerOnly) {\n // The header, and not one byte more. `headerChunks` holds whole 64KB chunks, so the tail\n // of the last one is whatever followed the delimiter; trimming it is what keeps this\n // constant-cost rather than \"the header plus up to 64KB of symbol table\".\n //\n // This returns before the memory check below on purpose. That check sizes the rows a call\n // will materialise, and this call materialises none - running it would let a file too\n // large to load refuse to report its own schema, which is the opposite of the point.\n //\n // _parseHeader runs next and re-derives the offsets from this buffer, exactly as it does\n // on the full path. Nothing downstream of it is reached, because there are no rows.\n this._headerBuffer = headerBuffer.subarray(0, headerEndIndex);\n this._emitProgress('read', 1, 1);\n return;\n }\n\n // A read of rows parses the header from here too, and reads the rest of the file as it goes.\n this._headerBuffer = headerBuffer.subarray(0, headerEndIndex);\n\n // Column count drives the largest term in the memory estimate, because what actually\n // exhausts the heap on a many-row file is one array per row plus one slot per cell - not the\n // symbol table, which for the commonest Qlik shape is tiny.\n //\n // A field selection is checked here, before anything large is read, and the count it produces\n // is what the memory guard is charged for. Both halves matter: an unknown field name costs\n // nothing to discover at this point, and charging a two-column projection for twenty columns\n // would refuse reads that fit ten times over.\n const selected = selectFields(headerFields, this._requestedFields, this._path);\n const columnCount = selected.length;\n // Two figures, because they answer two questions - see `_fieldsReadBy`. What the read will hold sizes\n // the heap; what it will read sizes the buffers it holds while parsing and the I/O it reports.\n const symbolBytes = symbolBytesOf(this._fieldsHeldAfter(selected, headerFields), symbolTableLength);\n const readSymbolBytes = symbolBytesOf(this._fieldsReadBy(selected), symbolTableLength);\n // What letting go of the file would release that this read does not need: the columns an earlier\n // page decoded and this one does not select. A cached column this read *does* select is needed\n // either way, so releasing it is no remedy and it does not count here.\n const retainedBytes = symbolBytesOf(\n this._fieldsHeldAfter(selected, headerFields).slice(selected.length),\n symbolTableLength,\n );\n\n // SAFETY CHECK: enough memory to materialise the rows this call will produce. Runs here,\n // before any large read, so a file too big to hold is refused rather than read and refused.\n // `headerNumbersUsable` and `_headerMatchesFile`, decided above, are what gate it.\n\n // Where the window really lands in this file, clamped to the rows it has.\n const resolved = headerNumbersUsable ? resolveWindow(window, totalRows) : {offset: 0, limit: 0};\n const windowRows = resolved.limit;\n\n if (headerNumbersUsable && this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolBytes,\n windowRows,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n columnCount,\n this._materialisesRows,\n liveRows,\n this._bytesHeld(\n readSymbolBytes,\n windowRows,\n recordSize,\n liveRows,\n this._analysisAhead(window, resolved, totalRows, symbolTableLength),\n symbolBytes - retainedBytes,\n ),\n // What it reads, which is not what it holds - the records go through one buffer and are not\n // kept. Carried so that a refusal's `check` says everything the pre-flight would have said.\n //\n // Twice over where the symbol-usage pass is still ahead of it: that pass reads the window's\n // records to find which symbols the rows use, and the decode then reads them again. Counted\n // once, the figure understated the I/O of exactly the reads that do the most of it.\n readSymbolBytes +\n readPasses(this._analysisAhead(window, resolved, totalRows, symbolTableLength)) * windowRows * recordSize,\n // A paging read keeps whole columns, so the estimate must not discount its symbols as a window's\n // sample of them - see `estimateMemoryUsage`. Under-charging is the direction that ends in a\n // heap-limit abort rather than an error.\n this._symbolCache !== null,\n retainedBytes,\n );\n }\n\n if (window.offset === 0 && window.limit === null) {\n // The whole file, and nothing more to read here: the symbol table and the records are read as\n // they are parsed. They used to be read here with the handle's `readFile()`, which Node caps at\n // 2 GiB, so every whole-file read of a larger QVD failed with its raw `RangeError` (#122).\n //\n // A file shorter than its header claims is found as it is parsed, with the errors a whole-file\n // read has always given: a symbol area past the end of the file is `Symbol data extends beyond\n // buffer`, an index table past it `Index table extends beyond the end of the file`.\n this._emitProgress('read', 1, 1);\n return;\n }\n\n const rowsToLoad = windowRows;\n\n // SAFETY CHECK: Very large symbol tables are still blocked to prevent OOM. Every read that is\n // not a whole-file read reaches here, which is the point at which it still costs nothing to\n // refuse: nothing past the header has been read yet, and the symbol table is read whole\n // whatever the window, because a stored index in any row can address any symbol.\n //\n // This deliberately does NOT distinguish `{offset: n, limit: m}` from `{offset: n}`. An\n // earlier revision of this work exempted the second, on the reasoning that a window bounded\n // only by an offset runs to the end of the file and so should be gated like a full read.\n // Measured on a 16,000-row fixture with a 153MB symbol table at a 288MB heap, that was wrong\n // in the uncatchable direction: `{offset: 15990, limit: 10}` was refused having allocated\n // nothing, at 53MB of RSS, while `{offset: 15990}` - the same ten rows - skipped this check,\n // passed the memory guard (whose symbol term is discounted by sqrt(windowRows/totalRows), so\n // it collapses for a small window), allocated and filled the whole 153MB buffer, and was only\n // then refused by the 50% ceiling in `_parseSymbolTable`. 207MB of RSS to read ten rows, and\n // inside a container sized below that it is a SIGKILL rather than an error.\n //\n // The exemption was also solving almost nothing. The band of symbol-table sizes where this\n // check refuses a read that a full load would have completed is bounded above by the memory\n // guard's own 6x symbol term: it is empty for any heap of 2GB or less, and 7MB wide at 4GB.\n validateSymbolTableSizeEarly(symbolBytes, this._path, retainedBytes);\n\n // Validate the header numbers before they are used to size anything. Without this, a NaN or\n // negative value reaches a read's length and surfaces as a raw Node RangeError.\n //\n // Through the functions a whole-file read validates them with later, so a window does not change\n // what a caller is told about the header. This used to report `Invalid header value: NoOfRecords`\n // where `fromQvd` without a window, `iterate` and `readMetadata` report `Invalid number of records`.\n // `Offset` needs no check here: `validateHeaderStructure` has refused an unusable one already.\n validateRecordSize(recordSize, this._path, 'readData');\n validateRecordCount(totalRows, this._path, 'readData');\n\n // What the file has to contain for the window to exist in it: the header, the symbol table, and\n // every record up to the window's last, since the window's records sit behind the ones it skips.\n // A window deep in a large file still reads only what it covers - the taxi fixture's last hundred\n // rows are a 0.4MB read rather than a 38MB one - but the file has to reach that far.\n const fileBytesRequired = indexTableOffset + (resolved.offset + rowsToLoad) * recordSize;\n\n // The header's numbers may not describe the file on disk: a truncated download, an interrupted\n // copy, a file still being written, or a header crafted to mislead. Refused here, before anything\n // past the header is read, with the message a window has always given for it.\n if (fileBytesRequired > fileSize) {\n throw new QvdCorruptedError('The file is shorter than its header claims.', {\n file: this._path,\n fileSize,\n requiredBytes: fileBytesRequired,\n stage: 'readData',\n });\n }\n\n this._emitProgress('read', 1, 1);\n }\n\n /**\n * Reads one byte range of the open file into a buffer.\n *\n * Read in bounded chunks, checking bytesRead each time. A single fs.read call with a length of\n * 2^31 or more does not throw - it trips a C++ assertion and aborts the whole process, which no\n * try/catch can intercept.\n *\n * @param {Buffer} target The buffer to read into.\n * @param {number} targetOffset Where in it to write.\n * @param {number} byteCount How many bytes to read.\n * @param {number} filePosition Where in the file to read from.\n * @param {number} requiredBytes How far into the file the read has to reach, for the error.\n * @throws {QvdCorruptedError} If the file ends before the range does.\n * @private\n */\n async _readAt(target, targetOffset, byteCount, filePosition, requiredBytes) {\n assert(this._handle && this._failed, 'The QVD file is not open.');\n\n const handle = this._handle;\n const failed = this._failed;\n let done = 0;\n\n while (done < byteCount) {\n const length = Math.min(READ_CHUNK_SIZE, byteCount - done);\n // @ts-ignore - Buffer type compatibility\n const {bytesRead} = await handle.read(target, targetOffset + done, length, filePosition + done).catch(failed);\n\n if (bytesRead === 0) {\n throw new QvdCorruptedError('Unexpected end of file while reading QVD data.', {\n file: this._path,\n fileSize: this._fileSize,\n // Two numbers, because they stopped being the same one when a window began reading two\n // ranges: `bytesRead` is how much of this range arrived, `filePosition` is where in the\n // file it gave up. Reporting the position under the name of the count made a windowed\n // read of a truncated file claim tens of megabytes had been read when a few hundred\n // bytes had.\n bytesRead: done,\n filePosition: filePosition + done,\n requiredBytes,\n stage: 'readData',\n });\n }\n\n done += bytesRead;\n }\n }\n\n /**\n * Bytes of the file a read holds outside the heap while it works, beside the codes the guard counts for\n * itself: the symbol areas it reads, and the one buffer its records come through.\n *\n * The areas are counted whole, although the read lets each range go once its fields are parsed, because\n * two ranges are both live when a field of one is parsed between two fields of the other - the order the\n * caller asked for the fields decides it, so the sum is what holds in every order. The slice is the\n * buffer `_forEachSlice` will allocate, sized by `_sliceRowsFor` so that the charge and the allocation\n * are one expression rather than two that agree today.\n *\n * @param {number} symbolBytes Bytes of symbols the read will read.\n * @param {number} rows Records it will read.\n * @param {number} recordSize Bytes per record.\n * @return {number} Bytes.\n * @private\n */\n _bytesHeldBy(symbolBytes, rows, recordSize) {\n const usable = Number.isSafeInteger(rows) && Number.isSafeInteger(recordSize) && rows > 0 && recordSize > 0;\n\n return symbolBytes + (usable ? this._sliceRowsFor(rows, recordSize) * recordSize : 0);\n }\n\n /**\n * Records the one buffer holds while a read of `rowCount` records goes through it.\n *\n * A slice is `sliceBytes` of records, rounded down to a whole record, or every record the read has left\n * when that is fewer - and at least one, since a read of a record wider than `sliceBytes` still has to\n * hold that record. The single definition: `_forEachSlice` allocates from it and the memory guard is\n * charged from it, so a change to how a read slices cannot leave the guard pricing the old rule.\n *\n * @param {number} rowCount Records the read will read.\n * @param {number} recordSize Bytes per record.\n * @return {number} Records in one slice.\n * @private\n */\n _sliceRowsFor(rowCount, recordSize) {\n return Math.max(1, Math.min(rowCount, Math.floor(this._sliceBytes / Math.max(1, recordSize))));\n }\n\n /**\n * What a read holds in bytes of the file, for the memory guard: what it holds now, and what a read\n * following either piece of advice a refusal can carry would hold instead.\n *\n * The two knobs are not the same knob, which is why there are two functions rather than one. A smaller\n * `limit` is a smaller window, so every record the read touches is one of fewer - the symbol-usage pass\n * included, since it reads the window. A smaller `chunkSize` leaves the window exactly where it is and\n * only changes how much of it is decoded at a time, so a read with that pass still ahead of it holds the\n * window's slice however small the chunk. Priced with `forRows`, such a chunk was charged for the records\n * of one chunk and then held sixteen megabytes more than that.\n *\n * @param {number} symbolBytes Bytes of symbols the read will read.\n * @param {number} windowRows Rows the read covers.\n * @param {number} recordSize Bytes per record.\n * @param {{rows: number, perChunk: number}|null} liveRows Rows held at one instant - see `_prepare`.\n * @param {boolean} analysisAhead Whether the symbol-usage pass has still to run.\n * @return {{held: number, forRows: (rows: number) => number, forChunk: (rows: number) => number}} What\n * this read holds, what a read of so many rows would hold, and what one reading so many rows a chunk\n * would hold.\n * @private\n */\n _bytesHeld(symbolBytes, windowRows, recordSize, liveRows, analysisAhead, freshSymbolBytes = null) {\n return {\n held: this._bytesHeldBy(symbolBytes, this._recordsAtOnce(windowRows, liveRows, analysisAhead), recordSize),\n // What it would hold having closed the file and opened it again: every selected column read fresh,\n // because nothing is cached any more. Higher than `held`, not lower - a cached column this read\n // selects costs nothing to read now and would cost its area then. Without it the counterfactual\n // that decides whether releasing helps was answered against the warm figure and said yes too often.\n afterRelease:\n freshSymbolBytes === null\n ? null\n : this._bytesHeldBy(freshSymbolBytes, this._recordsAtOnce(windowRows, liveRows, analysisAhead), recordSize),\n // A window of so many rows reads so many records at a time, and the pass that reads it ahead of the\n // decode reads the same rows, so the buffer is sized from the rows either way.\n forRows: (rows) => this._bytesHeldBy(symbolBytes, rows, recordSize),\n // A chunk of so many rows, over this read's window - which is what `chunkSize` changes and what it\n // leaves alone. `_recordsAtOnce` is what answers that, given a chunk size as the rows held at once.\n forChunk: (rows) =>\n this._bytesHeldBy(symbolBytes, this._recordsAtOnce(windowRows, {rows, perChunk: 1}, analysisAhead), recordSize),\n };\n }\n\n /**\n * Whether a read takes the symbol-usage pass, which reads the window's records before the symbol table\n * is parsed and so before the first chunk is built.\n *\n * The one statement of the condition. `_prepare` asks it to decide, and `_readData` asks it before the\n * header has been parsed, to know what to charge the memory guard: a read with the pass ahead of it\n * holds a whole slice of records, and a read without it holds only what it reads at a time. Said in two\n * places, the two would drift and a read would be charged for one path and take the other - which fails\n * open for a chunked read, and that is the direction the guard exists to prevent.\n *\n * Any window that does not cover the whole file is a candidate, which includes one bounded by its offset\n * rather than by its limit. Covering every row rules it out, however the window was spelled -\n * `{offset: 0, limit: n}` over all n rows, or an `iterate` of them. Such a read needs every symbol any\n * row uses, which is what `estimateMemoryUsage` assumes for a full read as well, so the pass has nothing\n * to filter. It is not free: since the records are read as they are decoded rather than held in one\n * buffer, the pass reads the window's records and the decode then reads them again. A window that really\n * is a window pays that for the symbols it saves parsing; a window that is a full read in disguise paid\n * it for nothing.\n *\n * The threshold is an option rather than a constant so this path can be exercised with a small fixture:\n * it is the most intricate code in the reader, and the only files large enough to reach the 50MB default\n * are ones no repository should be carrying around. It measures the whole table rather than the areas a\n * read selects, because what the pass saves is parsing work across the table.\n *\n * @param {QvdRowWindow} window The window as the caller spelled it.\n * @param {{offset: number, limit: number}} resolved Where it lands in this file.\n * @param {number} totalRows Rows the file declares.\n * @param {number} symbolTableLength The symbol table's declared length.\n * @return {boolean} Whether the pass will run.\n * @private\n */\n _analysisWouldRun(window, resolved, totalRows, symbolTableLength) {\n return (\n resolved.limit < totalRows &&\n (window.limit !== null || window.offset > 0) &&\n symbolTableLength > this._symbolFilteringThreshold\n );\n }\n\n /**\n * Records a read holds at one time, which is what its record buffer is sized from.\n *\n * A slice holds `sliceBytes` of records, or every record the read has left to read when that is fewer -\n * so what it costs depends on how many a read asks for at a time, not on how many it covers. An\n * iteration asks for a chunk: `iterate({limit: 20_000_000, chunkSize: 1000})` reads a thousand records at\n * a time however many its window covers, and charging it a full slice would refuse it for 16 MiB it never\n * allocates. The symbol-usage pass is the exception, because it reads the whole window in slices of its\n * own before the first chunk is built, so a read that still has that pass ahead of it is charged for it.\n *\n * @param {number} windowRows Rows the read covers.\n * @param {{rows: number, perChunk: number}|null} liveRows Rows held at one instant - see `_prepare`.\n * @param {boolean} analysisAhead Whether the symbol-usage pass has still to run.\n * @return {number} Records read at one time.\n * @private\n */\n _recordsAtOnce(windowRows, liveRows, analysisAhead) {\n const chunkRows =\n liveRows === null ? windowRows : Math.max(1, Math.floor(liveRows.rows / Math.max(1, liveRows.perChunk)));\n\n return analysisAhead ? Math.max(windowRows, chunkRows) : chunkRows;\n }\n\n /**\n * The fields this reader will be holding the symbols of once this read has finished.\n *\n * The ones it selects, and - while paging - the ones it decoded for an earlier page and kept. That\n * union is what the memory checks have to be sized by, because it is what is live: a reader four\n * pages into a wide file holds four columns' values whether or not this page asks about them, and a\n * check sized by this page alone would approve a fifth column that does not fit beside them.\n *\n * The same set for every check, so the ceilings, the guard and the pre-flight cannot disagree about\n * what a paging read costs. Without a cache it is just the selection, which is what every one-shot\n * read has always been sized by.\n *\n * @param {Array<any>} selected The fields this read selects.\n * @param {Array<any>} all Every field in the header, to find a cached one by name.\n * @return {Array<any>} The fields whose symbols will be live.\n * @private\n */\n _fieldsHeldAfter(selected, all) {\n if (this._symbolCache === null || this._symbolCache.size === 0) {\n return selected;\n }\n\n const names = new Set(selected.map((/** @type {any} */ field) => field['FieldName']));\n const cached = all.filter(\n (/** @type {any} */ field) =>\n !names.has(field['FieldName']) && this._symbolCache !== null && this._symbolCache.has(field['FieldName']),\n );\n\n return [...selected, ...cached];\n }\n\n /**\n * The fields whose symbol areas this read will actually read.\n *\n * The selection, less anything already decoded and kept. `_fieldsHeldAfter` answers what the read will\n * be *holding*, which is the right figure for the heap; this is the right one for the bytes it buffers\n * while parsing and for the I/O it reports, because a cached column's area is left out of the plan\n * entirely and never read.\n *\n * Sized by the wrong one of the two, a warm page was charged external bytes for buffers it never\n * allocates - and external bytes bind against a container limit, so a page that fits could be refused -\n * and `estimate.readBytes` claimed I/O it does not perform: on four columns with three cached it\n * reported 3,155,600 bytes for a read of 788,930.\n *\n * @param {Array<any>} selected The fields this read selects.\n * @return {Array<any>} The fields whose areas will be read.\n * @private\n */\n _fieldsReadBy(selected) {\n if (this._symbolCache === null || this._symbolCache.size === 0) {\n return selected;\n }\n\n return selected.filter(\n (/** @type {any} */ field) => this._symbolCache !== null && !this._symbolCache.has(field['FieldName']),\n );\n }\n\n /**\n * Keeps what this reader decodes, so that a later read of the same file does not decode it again.\n *\n * For a caller reading one file many times over - a `QvdFile` and its pages - and off by default,\n * because every other entry point is one read and would only be holding values nobody will ask for\n * again. Decoding the symbols is 72% of a page of a hundred rows from a 300,000-row file; the rest is\n * the open, the header, the records and the rows.\n *\n * It turns the two-pass symbol path off with it. That path decodes only the symbols a window's rows\n * use, which is right for one read and wrong for a cache: a later page asking for a row that uses a\n * skipped symbol would read `undefined` where the value is. So a cached field is always a whole\n * field, walked and checked against its `NoOfSymbols` like any other.\n *\n * @return {void}\n */\n beginPaging() {\n this._symbolCache = new Map();\n }\n\n /**\n * Reads with the fields the caller names for this read alone, rather than the reader's own.\n *\n * A `QvdFile` is opened once and its pages may each name a projection, so the selection cannot be\n * fixed at construction as it is for every other entry point.\n *\n * It holds until the next call replaces it rather than being cleared by the read, so **every caller\n * sets it before every read**, passing the file's own fields where the page named none. A caller that\n * relied on it being empty would instead get the projection of whatever ran last: that is what made a\n * `check()` naming no fields answer for the previous page's columns.\n *\n * @param {Array<string>|null|undefined} fields The fields, or undefined to use the reader's own.\n * @return {void}\n */\n selectForNextRead(fields) {\n if (fields !== undefined) {\n this._requestedFields = fields;\n }\n }\n\n /**\n * Watches the next read with the caller's `onProgress` and `signal`, rather than the reader's own.\n *\n * Both belong to one call, and a reader is told them when it is built - so a `QvdFile` page that named\n * either used to get a reader of its own. That made passing a progress callback change what the read\n * did rather than only observing it: a fresh reader is not paging, so it took the two-pass symbol\n * path, reported a different `loadStats.symbolFiltering`, and cached nothing. An observer must not\n * change what it observes, and a caller must not have to choose between cancelling a page and paging\n * cheaply.\n *\n * Like `selectForNextRead`, it holds until the next call replaces it rather than being cleared by the\n * read, so a caller that sets it for one page and not the next is still watched on the next - pass the\n * file's own watchers explicitly, as `QvdFile._page` does, rather than leaving them out.\n *\n * @param {{onProgress?: Function, signal?: AbortSignal}} [watchers] What this read is watched with.\n * @return {void}\n */\n observeNextRead({onProgress, signal} = {}) {\n // The same rules the constructor applies, because this is the same pair arriving by another door.\n // Assigning them unchecked put an `onProgress` of the wrong type past every check and into\n // `_emitProgress`, where it failed as a raw `TypeError` rather than a `QvdValidationError` naming\n // the option - and a signal-shaped object that is not one cancelled nothing, silently.\n validateWatchers(onProgress, signal, this._path);\n\n this._onProgress = onProgress;\n this._signal = signal;\n }\n\n /**\n * Whether the symbol-usage pass runs for this read, cache and all.\n *\n * `_analysisWouldRun` answers whether the window wants the pass; a paging read never takes it, because\n * a column decoded in part cannot be kept. Asked in one place because it was asked in two and they\n * disagreed: the pass was gated on the cache while the memory charge and `estimate.readBytes` were\n * not, so every page of a file above the threshold was charged a slice of records it never buffered\n * and reported twice the bytes it read.\n *\n * @param {QvdRowWindow} window The window as the caller spelled it.\n * @param {{offset: number, limit: number}} resolved Where it lands in this file.\n * @param {number} totalRows Rows the file declares.\n * @param {number} symbolTableLength The symbol table's declared length.\n * @return {boolean} Whether the pass will run.\n * @private\n */\n _analysisAhead(window, resolved, totalRows, symbolTableLength) {\n return this._symbolCache === null && this._analysisWouldRun(window, resolved, totalRows, symbolTableLength);\n }\n\n /**\n * Empties the cache when the header in front of us is not the one it was decoded from.\n *\n * The fingerprint is what a rewrite moves: the file's identity on disk - device, inode, modification\n * time and size - and then the header numbers, down to each cached field's own offset, length and\n * symbol count.\n *\n * The header numbers alone were not enough, and the gap is not exotic. `QvdFileWriter` carries\n * `CreateUtcTime` over from the metadata it is handed, so reading a QVD, changing one text to another\n * of the same byte length and writing it back leaves `CreateUtcTime`, `NoOfRecords`, `Offset` and\n * every field's `Offset`, `Length` and `NoOfSymbols` exactly as they were - a different file the\n * fingerprint could not tell from the first. The filesystem sees it either way: an atomic write\n * renames a new file into place, which changes the inode, and an in-place one moves `mtimeMs`.\n *\n * @return {void}\n * @private\n */\n _forgetCacheIfFileChanged() {\n if (this._symbolCache === null || this._symbolCache.size === 0) {\n return;\n }\n\n if (this._cachedFor !== this._fileFingerprint()) {\n this._symbolCache = new Map();\n this._cachedFor = null;\n }\n }\n\n /**\n * What identifies the file this reader's cache was decoded from.\n *\n * @return {string} The fingerprint.\n * @private\n */\n _fileFingerprint() {\n assert(this._header && this._allFields, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n\n return [\n // First, because it is the only part that moves when a rewrite preserves the header's numbers.\n this._fileIdentity,\n header['CreateUtcTime'],\n header['NoOfRecords'],\n header['Offset'],\n ...this._allFields.map(\n (/** @type {any} */ field) =>\n `${field['FieldName']}:${field['Offset']}:${field['Length']}:${field['NoOfSymbols']}`,\n ),\n ].join('|');\n }\n\n /**\n * Drops everything this reader has decoded, so that nothing outlives the caller that wanted it.\n *\n * @return {void}\n */\n endPaging() {\n this._symbolCache = null;\n this._cachedFor = null;\n }\n\n /**\n * The symbol table's length, as much of it as the file holds: what the header declares, cut short where\n * the file ends. Known before a byte of the table is read, so everything that can refuse the table is\n * checked on this, before the table is allocated.\n *\n * A file that ends inside its symbol table is measured to where it ends, and the fields whose areas it cut\n * short are refused as `Symbol data extends beyond buffer` when their metadata is checked - what a\n * whole-file read has always said of such a file. A window has refused it already, before reading anything.\n *\n * @return {number} Bytes.\n * @private\n */\n _symbolTableLength() {\n assert(\n this._symbolTableOffset !== null && this._indexTableOffset !== null && this._fileSize !== null,\n 'The QVD file header has not been parsed before its symbol table was measured.',\n );\n\n const declared = this._indexTableOffset - this._symbolTableOffset;\n\n return Math.max(0, Math.min(declared, this._fileSize - this._symbolTableOffset));\n }\n\n /**\n * Where each selected field's symbols are, as ranges of the symbol table this read will read.\n *\n * A field's `Offset` and `Length` say exactly where its symbols are, so a read of some of a file's fields\n * has no reason to read the areas of the rest (#122). Qlik writes the areas one after another in field\n * order, so ranges that touch are merged: a read of every field is one range, and so is a read of fields\n * that happen to be neighbours. A read of one field of twenty reads that field's area alone.\n *\n * A field whose symbols this reader already holds is left out, because its bytes are not wanted: the\n * ranges are what gets read, and including a cached field's span had a page read every byte of every\n * column it named, cached or not. Measured on four columns of 20,000 distinct texts, a page naming all\n * four with three of them cached read all four columns' bytes - 1,155,600 of them, where 288,930 were\n * needed. The decode was saved and the I/O was not, which on the files #122 is about is the whole cost.\n *\n * Built once per read, from the fields the read must read, and each field's metadata is checked as it is\n * added - a range is arithmetic on `Offset` and `Length`, and those have to be inside the table first.\n * `_parseSymbolTable` checks every field of the file, selected or not, before it parses any.\n *\n * @return {{ranges: Array<{start: number, end: number, fields: number, buffer: Buffer|null}>,\n * byField: Map<any, {range: {start: number, end: number, fields: number, buffer: Buffer|null},\n * start: number, end: number}>}} The ranges, and where in its range each field's area sits.\n * @private\n */\n _symbolAreaPlan() {\n if (this._symbolAreas !== null) {\n return this._symbolAreas;\n }\n\n assert(this._selectedFields, 'The QVD file fields have not been resolved before their symbols were read.');\n\n const tableLength = this._symbolTableLength();\n const toRead = this._selectedFields.filter(\n (/** @type {any} */ field) => this._symbolCache === null || !this._symbolCache.has(field['FieldName']),\n );\n const areas = toRead.map((/** @type {any} */ field) => {\n validateFieldMetadata(field, tableLength, this._path);\n\n const start = headerInteger(field['Offset']);\n\n return {field, start, end: start + headerInteger(field['Length'])};\n });\n\n /** @type {Array<{start: number, end: number, fields: number, buffer: Buffer|null}>} */\n const ranges = [];\n /** @type {Map<any, {range: any, start: number, end: number}>} */\n const byField = new Map();\n\n for (const area of [...areas].sort((a, b) => a.start - b.start)) {\n const last = ranges.at(-1);\n // Merged when this area begins where the last one ended, or inside it. Overlapping areas are refused\n // by `validateSymbolAreas` before anything is parsed; merging them here only decides what is read.\n const range =\n last !== undefined && area.start <= last.end\n ? last\n : {start: area.start, end: area.end, fields: 0, buffer: null};\n\n if (range !== last) {\n ranges.push(range);\n }\n\n range.end = Math.max(range.end, area.end);\n range.fields += 1;\n byField.set(area.field, {range, start: area.start, end: area.end});\n }\n\n this._symbolAreas = {ranges, byField};\n\n return this._symbolAreas;\n }\n\n /**\n * One field's symbols, as bytes: the range that holds them, read from the open file the first time a field\n * of that range needs it.\n *\n * @param {any} field The field, one this read selected.\n * @return {Promise<{buffer: Buffer, start: number, end: number, base: number}>} Its area, as a range of\n * `buffer`, with where that buffer starts in the symbol table - what an error adds back to say where a\n * damaged symbol is in the file, rather than where it is in the bytes this read happened to read.\n * @throws {QvdValidationError} If the range is larger than half the heap.\n * @private\n */\n async _symbolAreaOf(field) {\n assert(\n this._header && this._symbolTableOffset !== null,\n 'The QVD file header has not been parsed before its symbols were read.',\n );\n\n const area = this._symbolAreaPlan().byField.get(field);\n\n assert(area, 'A field this read did not select has no symbol area.');\n\n const {range} = area;\n\n if (range.buffer === null) {\n const length = range.end - range.start;\n\n // The ceiling `_parseSymbolTable` applies, here as well because the two-pass count reads a field's\n // symbols before that runs. Before the allocation, where it used to come after the table had been\n // read: a whole-file read makes no early check, and the memory guard stands aside when the header\n // does not describe the file, so a damaged header in a large file was allocated whatever it claimed,\n // up to the size of the file.\n validateSymbolTableSize(length, this._path, headerInteger(this._header['QvdTableHeader']['NoOfRecords']));\n\n // Zero-filled rather than allocUnsafe: if any path ever failed to overwrite part of it, the result\n // would be zeros rather than leaked process memory.\n const buffer = Buffer.alloc(length);\n const from = this._symbolTableOffset + range.start;\n\n await this._readAt(buffer, 0, length, from, from + length);\n\n range.buffer = buffer;\n }\n\n return {buffer: range.buffer, start: area.start - range.start, end: area.end - range.start, base: range.start};\n }\n\n /**\n * Lets go of a field's symbols once they are parsed, and of the bytes of its range once every field in it\n * has been.\n *\n * Every text is copied out of the bytes as it is decoded, so what the read keeps is the values. A read of\n * one field of a file whose other fields are large therefore holds that field's bytes and no others.\n *\n * @param {any} field The field whose symbols are parsed.\n * @private\n */\n _releaseSymbolArea(field) {\n const area = this._symbolAreaPlan().byField.get(field);\n\n assert(area, 'A field this read did not select has no symbol area.');\n\n area.range.fields -= 1;\n\n if (area.range.fields === 0) {\n area.range.buffer = null;\n }\n }\n\n /**\n * Reads records from the open file a slice at a time, and hands each slice to `visit`.\n *\n * One buffer of at most `sliceBytes` holds a slice, and is reused for the next one, so a read of any\n * number of records holds that much of them and no more. Cancellation is checked before each slice.\n *\n * @param {number} firstRow The file row of the first record.\n * @param {number} rowCount How many records.\n * @param {number} recordSize Bytes per record.\n * @param {(slice: Buffer, done: number, count: number) => void|Promise<void>} visit Called with each\n * slice's records, how many records came before it, and how many it holds.\n * @private\n */\n async _forEachSlice(firstRow, rowCount, recordSize, visit) {\n if (rowCount === 0) {\n return;\n }\n\n assert(this._indexTableOffset !== null, 'The QVD file header has not been parsed before its records were read.');\n\n const sliceRows = this._sliceRowsFor(rowCount, recordSize);\n const slice = Buffer.alloc(sliceRows * recordSize);\n const requiredBytes = this._indexTableOffset + (firstRow + rowCount) * recordSize;\n\n for (let done = 0; done < rowCount; done += sliceRows) {\n this._throwIfAborted();\n\n const count = Math.min(sliceRows, rowCount - done);\n const records = slice.subarray(0, count * recordSize);\n\n await this._readAt(\n records,\n 0,\n records.length,\n this._indexTableOffset + (firstRow + done) * recordSize,\n requiredBytes,\n );\n await visit(records, done, count);\n }\n }\n\n /**\n * Parses the XML header of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n */\n async _parseHeader() {\n if (!this._headerBuffer) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const HEADER_DELIMITER = '\\r\\n\\0';\n\n const headerBeginIndex = 0;\n const headerDelimiterIndex = this._headerBuffer.indexOf(HEADER_DELIMITER, headerBeginIndex);\n\n // Check explicitly for -1 (not found) rather than using falsy check (!headerDelimiterIndex)\n // because indexOf() returns 0 when the delimiter is at position 0, which is a valid buffer index.\n // Using !0 would incorrectly treat position 0 as an error.\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n const headerBuffer = this._headerBuffer.subarray(headerBeginIndex, headerEndIndex);\n\n /*\n * The following instruction parses the XML header into a JSON object. It is important to\n * note that the object is a plain JavaScript object and not an instance of representative\n * class. Hence, types are not casted, therefore all raw values are strings, and child nodes\n * that contain an array of objects are not represented directly as an array but as an object\n * with a property, named like the array item tag, that is an array of the actual objects. The\n * same applies to child nodes that contain a single object and the root node.\n *\n * The following XML representation of the QVD header for example...\n *\n * <QvdTableHeader>\n * ...\n * <Fields>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * </Fields>\n * </QvdTableHeader>\n *\n * ...is parsed into the following object:\n *\n * {\n * QvdTableHeader: {\n * ...,\n * Fields: {\n * QvdFieldHeader: [\n * { FieldName: 'Field1', ...},\n * { FieldName: 'Field2', ...}\n * ]\n * }\n * }\n * }\n */\n\n // A header nobody has checked yet. Cleared before the parse, so that whatever happens next nothing\n // trusts the verdict on the last one. A reader is not single-use: a second read parses the file's\n // header again, and the file may have been replaced in between. When the flag survived that, a\n // second read of other fields only decoded a new, unchecked header - a Bias out of range included.\n this._fieldBitMetadataValidated = false;\n\n this._header = await parseHeaderXml(headerBuffer.toString(), this._path, 'parseHeader');\n\n // The field list, checked - a list of field elements, each with a name no other has - so every\n // path downstream can assume one. Checked once, at the point the header becomes available.\n const fieldList = validateHeaderStructure(this._header, this._path, 'parseHeader');\n\n /*\n * Because the three parts of the QVD file, header, symbol and index table, are seamlessly concatenated,\n * the end of the respective previous part is the beginning of the next part.\n */\n this._headerOffset = headerBeginIndex;\n this._symbolTableOffset = headerEndIndex;\n this._indexTableOffset = this._symbolTableOffset + headerInteger(this._header['QvdTableHeader']['Offset']);\n\n // The file's fields, and the caller's selection of them, resolved once and here.\n //\n // Everything downstream is positionally aligned by the order `selectFields` returns - the\n // symbol table, the decoded columns and `columns` are three arrays indexed by the same\n // position - so they have to come from one derivation rather than from three that happen to\n // agree. That is the same rule `fieldGeometry` exists to enforce for the bit layout, and the\n // consequence of breaking it is the same: a misalignment decodes cleanly and returns another\n // column's values with nothing thrown.\n // `fieldList` as `validateHeaderStructure` returned it, rather than normalised again here: it is\n // already an array of named field elements, so recomputing it would be a second derivation that\n // happens to agree - which is the thing this caching exists to stop, one scope up.\n this._allFields = fieldList;\n this._selectedFields = selectFields(this._allFields, this._requestedFields, this._path);\n }\n\n /**\n * Establishes the geometry of the index table, and validates it.\n *\n * Both passes over the index table - the symbol-usage analysis and the decode itself - need\n * exactly this, and they used to derive it separately with two copies of the same bit\n * unpacking. The copies are the reason the bias comment in the analysis pass warns so loudly\n * about keeping the sign in step with the other one: the two could drift, and #113 is what\n * that looks like when they do. There is one copy now.\n *\n * @param {QvdRowWindow} window The rows of interest, as file row indices.\n * @param {string} stage Stage name for any error raised here.\n * @return {{fields: Array<any>, recordSize: number, totalRows: number, rowsToLoad: number,\n * firstRow: number}} The record geometry: the window's `rowsToLoad` records start at file row\n * `firstRow`, and `_forEachSlice` reads them.\n * @private\n */\n _planIndexTable(window, stage) {\n if (!this._handle || !this._header || !this._indexTableOffset || !this._selectedFields || !this._allFields) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage,\n },\n );\n }\n\n const allFields = this._allFields;\n const fields = this._selectedFields;\n\n // Size of a single row of the index table in bytes\n const recordSize = headerInteger(this._header['QvdTableHeader']['RecordByteSize']);\n const totalRows = headerInteger(this._header['QvdTableHeader']['NoOfRecords']);\n const indexTableLength = headerInteger(this._header['QvdTableHeader']['Length']);\n\n // Resolved again rather than trusted. Callers already pass a window resolved against this\n // file, and resolving a resolved window returns it unchanged - but this is the function that\n // decides which bytes get decoded, and it should not be possible to reach it with a window\n // that runs off the end of the file.\n const {offset: firstRow, limit: rowsToLoad} = resolveWindow(window, totalRows);\n\n assert(this._fileSize !== null, 'The QVD file has not been measured before its records were planned.');\n\n // Validate all index table metadata, against the file: the records are read from it as they are\n // decoded, so it is the file that has to hold them. A whole-file read used to check against a\n // buffer holding the whole file, which is the same thing, so its messages are unchanged.\n validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n this._indexTableOffset,\n this._fileSize,\n rowsToLoad,\n this._path,\n this._fileSize,\n firstRow,\n 0,\n );\n\n // Validate BitOffset and BitWidth for every field in the file, selected or not, once.\n //\n // A projection must not make a corrupt file readable: if a field's bit metadata is nonsense,\n // `{fields: [...]}` that happens to leave it out should not quietly succeed where a full read\n // refuses. The check costs nothing - it reads header numbers - and keeping it whole means one\n // answer to \"does this file decode\".\n //\n // Once per header, not once per window: the metadata is the header's and does not change\n // between chunks, so a 200-chunk iteration over 20 fields was re-parsing the same 4,000\n // strings. `_parseHeader` clears the flag, so a reader reused on a file that has changed\n // checks the new header. It stays *here*, after validateIndexTableMetadata, rather than\n // moving up into `_prepare` - that call is what establishes `recordSize` is usable, and\n // validating bit offsets against an unusable record size reports the wrong fault for the\n // same file.\n if (!this._fieldBitMetadataValidated) {\n for (const field of allFields) {\n validateFieldBitMetadata(field, recordSize, this._path);\n }\n\n // After every field has passed on its own, so a field that runs past the record is reported as\n // that rather than as overlapping whatever it ran into.\n validateBitFields(allFields, this._path);\n\n this._fieldBitMetadataValidated = true;\n }\n\n // The decoder indexes into each slice without per-row bounds checks, which is only sound because\n // every slice holds whole records: `_forEachSlice` reads them whole, and refuses a file that ends\n // before they do. validateIndexTableMetadata has already established that the file holds the\n // window's `rowsToLoad` records - the declared table reaches the end of the window, and the file\n // holds the declared table.\n //\n // Stated as an assertion rather than dropped, because relaxing any of those checks later would\n // make a read fall short of the window, and a record that is not there would decode as whatever\n // the slice held before. Better to fail here.\n const windowEnd = this._indexTableOffset + (firstRow + rowsToLoad) * recordSize;\n assert(\n rowsToLoad === 0 || recordSize === 0 || windowEnd <= this._fileSize,\n `The window's records end at byte ${windowEnd} of a file of ${this._fileSize}, ` +\n `but ${rowsToLoad} were validated as present.`,\n );\n\n return {fields, recordSize, totalRows, rowsToLoad, firstRow};\n }\n\n /**\n * Analyzes the index table to determine which symbols are actually needed.\n * This is used for two-pass symbol filtering optimization.\n *\n * Only the selected fields are analysed. An unselected field's symbols are never parsed, so\n * there is nothing for a usage set to filter and decoding its column would be a pass over the\n * whole window for an answer nobody reads.\n *\n * @param {QvdRowWindow} window The rows to analyse.\n * @return {Promise<Array<Set<number>>>} One set of needed symbol indices per selected field, in\n * the same order `_parseSymbolTable` walks them.\n * @private\n */\n async _analyzeIndexTableSymbolUsage(window) {\n const {fields, recordSize, rowsToLoad, firstRow} = this._planIndexTable(window, 'analyzeIndexTableSymbolUsage');\n\n // One set per field, indexed by position rather than keyed by field name.\n //\n // By position because every other per-field array in this reader is - the symbol table, the\n // decoded columns and `columns` are all indexed the same way - and a name-keyed map is not\n // the same thing when a header declares two fields with one name. Qlik does not produce such\n // a file, and `validateHeaderStructure` now refuses one, but while nothing did, keying by name\n // made the second field's set overwrite the first's: the first field was then filtered against\n // the wrong set, every symbol it needed and the other did not read back as `undefined`, and\n // nothing threw. Measured on a copy of `lego/colors.qvd` with a field renamed to collide: a\n // plain read gave `'Black'` where a filtered read gave `undefined`. It only bit above\n // `symbolFilteringThreshold`, which is to say only on the large files where it is hardest to\n // notice - the #113 failure shape exactly.\n /** @type {Array<Set<number>>} */\n const symbolUsage = [];\n\n // One slice of one column at a time, reused across every slice and every field.\n //\n // Bounded rather than sized to the window, because the answer this pass produces is a *set*\n // of distinct indices: the union over slices is the same set the whole window would give, so\n // there is no reason to hold the window. Sizing it to the window made the pass allocate four\n // bytes per row of a read whose entire purpose might be to hold only a chunk at a time -\n // `iterate({limit: 20_000_000, chunkSize: 1000})` allocated 80MB here while the memory guard\n // had been told the read holds 2,000 rows. A cgroup counts that 80MB and answers with a\n // SIGKILL, which is the uncatchable direction.\n //\n // Capping it is the fix rather than telling the guard about it: an allocation the guard has\n // to be told about is one more figure that can drift from what the code does, and this one\n // did not need to exist.\n const sliceRows = Math.min(rowsToLoad, ANALYSIS_SLICE_ROWS);\n const column = new Int32Array(sliceRows);\n\n // What the pass knows of each field so far. The records are read a slice at a time and every field\n // is decoded from each slice before the next is read, so this lives across slices.\n const state = fields.map((/** @type {any} */ field) => {\n const needed = new Set();\n symbolUsage.push(needed);\n\n // The bias is applied inside the decoder, which is the same call the parse pass makes.\n // When these were two separate unpackings, a sign difference here would have recorded the\n // wrong symbols as needed and every affected cell would have read back as undefined -\n // silently, because such an index still addresses a symbol, just one this pass left out.\n //\n // Decoded unchecked: the symbols are not parsed yet, so there is no count to check against.\n // `_parseIndexTable` decodes the same rows with the check and refuses an index that\n // addresses nothing. Until then it only has to be kept out of `needed`, which is not\n // harmless to fill: a damaged index table can hold a different index in every row.\n //\n // No index at or past `indexLimit` can address a symbol, so none is kept. It starts as the\n // most symbols the field's bytes can hold - each takes at least two, a type byte and the\n // terminator of an empty string - which costs nothing to know. That is not the symbols the\n // field has, though, so once `needed` outgrows `COUNT_SYMBOLS_PAST` they are counted and it\n // becomes that. Either way no index it leaves out could have addressed a symbol. An unusable\n // `Length` bounds nothing here, and `_parseSymbolTable` refuses the field anyway.\n //\n // The header's `NoOfSymbols` is not the start, although the parse refuses a field that does not\n // hold that many. It would keep the same set on a valid file, whose indices are all below it, and\n // it would not spare the count: one too large bounds nothing, and only the walk shows it is wrong.\n const length = headerInteger(field['Length']);\n\n return {\n field,\n needed,\n bitOffset: headerInteger(field['BitOffset']),\n bitWidth: headerInteger(field['BitWidth']),\n bias: headerInteger(field['Bias']),\n indexLimit: Number.isSafeInteger(length) && length >= 0 ? Math.ceil(length / 2) : Infinity,\n counted: false,\n };\n });\n\n await this._forEachSlice(firstRow, rowsToLoad, recordSize, async (records, done, recordCount) => {\n for (let first = 0; first < recordCount; first += sliceRows) {\n const count = Math.min(sliceRows, recordCount - first);\n\n for (const field of state) {\n // The decoder always counts records from the start of the buffer it is given, so a slice\n // is a matter of where that buffer starts - the same property that makes a row window\n // cheap in `_parseIndexTable`.\n decodeIndexColumn(\n first === 0 ? records : records.subarray(first * recordSize),\n recordSize,\n count,\n field.bitOffset,\n field.bitWidth,\n field.bias,\n column,\n );\n\n for (let row = 0; row < count; row++) {\n // A negative index references no symbol - it is NULL, or damage the decode refuses - and\n // neither does one at or past `indexLimit`, so neither is kept.\n if (column[row] >= 0 && column[row] < field.indexLimit) {\n field.needed.add(column[row]);\n }\n }\n\n // Checked once a slice rather than once a row, which keeps the loop above to what it was:\n // the set can outgrow the threshold by one slice at most before it is held to the count.\n if (!field.counted && field.needed.size > COUNT_SYMBOLS_PAST) {\n field.counted = true;\n field.indexLimit = Math.min(field.indexLimit, await this._countFieldSymbols(field.field));\n\n for (const index of field.needed) {\n if (index >= field.indexLimit) {\n field.needed.delete(index);\n }\n }\n }\n }\n }\n\n // Rows analysed, over the rows the window covers: the records are read once for every field, so a\n // field at a time is no longer the unit of progress.\n this._emitProgress('symbol-analysis', done + recordCount, rowsToLoad);\n });\n\n if (rowsToLoad === 0) {\n this._emitProgress('symbol-analysis', 0, 0);\n }\n\n return symbolUsage;\n }\n\n /**\n * How many symbols a field holds, for the symbol-usage pass, which runs before the symbols are parsed.\n *\n * The count is `countFieldSymbols`, the parse itself told to decode nothing, so it is the count\n * `_parseSymbolTable` will produce and `_parseIndexTable` will check against. The field's area is\n * validated before it is read, by `_symbolAreaPlan`, so a damaged `Offset`, `Length` or `NoOfSymbols` is\n * reported the same way wherever it is met. Its bytes are kept for the parse that follows. The walk checks the count against `NoOfSymbols` as the\n * parse does, so a field whose count is wrong is refused here, before the pass keeps anything on the\n * strength of it.\n *\n * @param {any} field The field's header.\n * @return {Promise<number>} Its symbols.\n * @throws {QvdCorruptedError} If the area is not inside the symbol table, a symbol runs past it, or it\n * holds a different number of symbols from its `NoOfSymbols`.\n * @private\n */\n async _countFieldSymbols(field) {\n const area = await this._symbolAreaOf(field);\n\n return countFieldSymbols(\n area.buffer,\n area.start,\n area.end,\n headerInteger(field['NoOfSymbols']),\n field['FieldName'],\n this._path,\n area.base,\n );\n }\n\n /**\n * Parses the symbol table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * A field the caller did not select is skipped whole. Its symbol area is neither scanned nor\n * parsed - the per-field `Offset` and `Length` say exactly where it is, so there is nothing to\n * walk past - and that is where field selection earns its keep. The index decode is cheap by\n * comparison; parsing symbols is not.\n *\n * @param {Array<Set<number>>|null} symbolsToKeep Optional set of symbol indices to keep per\n * selected field, indexed by position. If provided, only these symbols will be parsed\n * (two-pass filtering optimization).\n * @param {number} rowsToLoad Rows the read covers, for memory estimation.\n * @param {{rows: number, perChunk: number}|null} [liveRows=null] Rows held at one instant when\n * that is fewer than the window covers - see `_prepare`.\n */\n async _parseSymbolTable(symbolsToKeep = null, rowsToLoad = 0, liveRows = null) {\n if (\n !this._handle ||\n !this._header ||\n !this._symbolTableOffset ||\n !this._indexTableOffset ||\n !this._selectedFields ||\n !this._allFields\n ) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseSymbolTable',\n },\n );\n }\n\n const allFields = this._allFields;\n const fields = this._selectedFields;\n\n // The cache holds values decoded from one file, and a page re-opens the path rather than holding it,\n // so the file underneath can be replaced between pages - an upstream job rewriting it in place. Its\n // name would still match, and the old values would be used to resolve the new file's row codes:\n // plausible rows, silently wrong, which is the failure this library builds checks against (#124,\n // #247). Cheap to rule out, because the header is re-read for every page anyway.\n this._forgetCacheIfFileChanged();\n\n // Measured, not read: every check up to the parse needs only the length, so bytes one of them refuses\n // are never allocated. They are read once the checks have all passed.\n //\n // Two lengths, because two different things are being bounded. The ceiling bounds what this read will\n // hold - the areas of the fields it selects, which is the whole table only when it selects them all -\n // and `_symbolTableLength` bounds where those areas may sit, which is the table however few are read.\n //\n // The plan is built before the ceiling below rather than after it, and deliberately: the ceiling is\n // sized from the areas, and `_symbolAreaPlan` is what validates them - an area whose `Offset` or\n // `Length` is not a usable number, or that sits outside the table, is refused there. Sizing a check\n // from numbers nothing has checked is how a header talks its way past one. The visible consequence is\n // which error a file damaged in two ways at once reports: one whose fields are unusable *and* whose\n // table exceeds the ceiling is now refused for the fields, where before 2.0.6 it was refused for the\n // size. Both are true of it; the field error is the more specific, and it names the field.\n const symbolTableSize = this._symbolTableLength();\n const plan = this._symbolAreaPlan();\n\n // The areas this read will read, plus the columns an earlier page left decoded and live. The plan\n // covers only what is about to be read, which is the right number for the areas but the wrong one\n // for what the read will be holding when it finishes.\n const readSymbolBytes = plan.ranges.reduce((sum, range) => sum + (range.end - range.start), 0);\n const retainedBytes = symbolBytesOf(this._fieldsHeldAfter(fields, allFields).slice(fields.length), symbolTableSize);\n const symbolBytes = readSymbolBytes + retainedBytes;\n const totalRows = headerInteger(this._header['QvdTableHeader']['NoOfRecords']);\n const recordSize = headerInteger(this._header['QvdTableHeader']['RecordByteSize']);\n\n // SAFETY CHECK 1: Absolute ceiling to prevent pathological cases\n // Phase 2.5 optimization allows much larger symbol tables when using maxRows,\n // but we still need an absolute maximum to prevent truly extreme cases\n validateSymbolTableSize(symbolBytes, this._path, totalRows);\n\n // SAFETY CHECK 2: Dynamic memory validation, now against the symbol table's real size rather\n // than the size its header declared. _readData already ran this check before reading\n // anything; this is the more accurate second look, and the two agree on a well-formed file.\n //\n // Skipped on the same condition as the early one. This is the call that mattered: the\n // structural checks that identify a truncated file run in _parseIndexTable, after this, so\n // an estimate built on an inflated NoOfRecords would report a memory problem for a file\n // whose real problem is that it is short.\n if (this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolBytes,\n rowsToLoad,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n fields.length,\n this._materialisesRows,\n liveRows,\n this._bytesHeld(readSymbolBytes, rowsToLoad, recordSize, liveRows, false, symbolBytes - retainedBytes),\n // `symbolsToKeep` is non-null exactly when the symbol-usage pass has run, and a pass that has\n // run has read the window's records once already - so the read's total is two passes over them.\n readSymbolBytes + readPasses(symbolsToKeep !== null) * rowsToLoad * recordSize,\n this._symbolCache !== null,\n retainedBytes,\n );\n }\n\n // WARNING ZONE: Large files without maxRows parameter\n // Educate users about best practices but don't block\n warnLargeSymbolTable(\n symbolBytes,\n rowsToLoad,\n totalRows,\n fields.length,\n this._materialisesRows,\n this._symbolCache !== null,\n );\n\n /*\n * The symbol table is a contiguous byte array that contains all possible symbols/values of all fields/columns.\n * The symbols/values of one field are stored consecutively in the same order as the fields/columns are defined\n * in the header. The length of the symbol area as well as it's offset, relativ to the begin of the symbol\n * table, are also defined in the header.\n */\n\n // Validate every field's metadata, selected or not, to prevent buffer overflow attacks.\n //\n // Whole-file rather than whole-selection for the same reason the bit metadata is: a\n // projection must not turn a file a full read refuses into one it accepts. Reading header\n // numbers costs nothing next to parsing the symbols they describe.\n //\n // Then the areas against each other, once each is known to be inside the table: two fields whose\n // areas overlap would each parse some of the other's symbols as their own.\n for (const field of allFields) {\n validateFieldMetadata(field, symbolTableSize, this._path);\n }\n\n validateSymbolAreas(allFields, this._path);\n\n // Decode the symbols of each *selected* field, straight from the bytes into their two halves. Each\n // field's bytes are read when its turn comes, and let go of once they are decoded, so a read holds the\n // values it has parsed and the bytes of at most one range of the table. Phase 2.5 optimization: a symbol\n // the window does not use is walked past without decoding.\n //\n // Assigned when every field has parsed, rather than field by field, so a read refused part-way leaves\n // the reader describing no symbol table rather than half of one.\n /** @type {Array<import('./util/symbolParser.js').FieldSymbols>} */\n const symbolTable = [];\n\n for (const [position, field] of fields.entries()) {\n this._throwIfAborted();\n\n // A field this reader has already decoded, when it is paging. Measured on a 300,000-row file with\n // a 50,000-value text column, decoding the symbols is 72% of a page of a hundred rows - so a\n // viewer that pages through one file re-did, per page, nearly all the work of the page before it.\n //\n // Only whole fields are cached, and only a read that decoded all of a field's symbols may put one\n // in: `symbolsToKeep` means the walk skipped some, and a later page asking for a row that uses a\n // skipped symbol would read `undefined` from the cache rather than its value. `beginPaging` turns\n // the two-pass path off for that reason, so a cached field is always whole.\n const cached = this._symbolCache?.get(field['FieldName']);\n\n if (cached) {\n symbolTable.push(cached);\n this._emitProgress('symbol-table', position + 1, fields.length);\n continue;\n }\n\n const area = await this._symbolAreaOf(field);\n const parsed = parseFieldSymbols(\n area.buffer,\n area.start,\n area.end,\n // Checked against the symbols the area holds, which is the one check that sees a terminator\n // damaged in the middle of it (#124). A cached field was checked when it was decoded, which is\n // why the cache may only hold a field a full walk produced.\n headerInteger(field['NoOfSymbols']),\n // By position, matching how `_analyzeIndexTableSymbolUsage` built it. Both walk\n // `this._selectedFields`, so position is the one key that cannot collide.\n symbolsToKeep ? symbolsToKeep[position] : null,\n field['FieldName'],\n this._path,\n undefined,\n area.base,\n );\n\n symbolTable.push(parsed);\n\n if (this._symbolCache && symbolsToKeep === null) {\n if (this._symbolCache.size === 0) {\n this._cachedFor = this._fileFingerprint();\n }\n\n this._symbolCache.set(field['FieldName'], parsed);\n }\n\n this._releaseSymbolArea(field);\n this._emitProgress('symbol-table', position + 1, fields.length);\n }\n\n this._symbolTable = symbolTable;\n }\n\n /**\n * Parses the bit stuffed index table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * One `Int32Array` per field, filled by `decodeIndexColumn`, replacing an array per row filled\n * a bit at a time. The old route, per row, built an `Int32Array` of the record's bytes,\n * concatenated a binary string of `recordSize * 8` characters, split it into a character\n * array, reversed that, and mapped it to one number per *bit*; then per cell it sliced the\n * result again and summed `bit * Math.pow(2, index)`. Several arrays the length of the record\n * in bits, built and discarded for every row.\n *\n * Column-major is what makes the decode tight: a field's bit offset, width and bias are the\n * same for every row, so they are hoisted out of the loop and the inner loop does arithmetic\n * into a typed array and nothing else. Rows are assembled later, once, in `load()`.\n *\n * The window is what makes chunked iteration cheap: `decodeIndexColumn` walks records by\n * `base += recordSize`, so decoding rows k to k+n is a question of where the buffer slice starts\n * and how many iterations run. Nothing about the decoder changed to support it.\n *\n * Every index is checked as it is decoded. One that addresses neither a symbol of its field nor\n * NULL throws a `QvdCorruptedError` naming the file row (#125). Here and not where rows or columns\n * are built, because every read decodes through this method and a columnar read hands its codes\n * straight to the caller. Rows outside the window are not decoded, so they are not checked.\n *\n * @param {QvdRowWindow} window The rows to decode.\n * @param {number} [progressBase=0] Rows decoded before this call, so that progress over a chunked\n * iteration counts the whole window rather than restarting at every chunk - what `_buildRows` takes\n * for the same reason.\n * @param {number|null} [progressTotal=null] Rows the whole window covers, or null for this call's own.\n * @param {Array<Int32Array>|null} [into=null] Arrays to decode into, one per selected field and at least\n * `limit` long, for a caller that decodes chunk after chunk and keeps none of them. Null allocates.\n * @throws {QvdCorruptedError} If an index in the window addresses neither a symbol nor NULL.\n */\n async _parseIndexTable(window, progressBase = 0, progressTotal = null, into = null) {\n const {fields, recordSize, rowsToLoad, firstRow} = this._planIndexTable(window, 'parseIndexTable');\n\n // Rows decoded before this call, and rows the whole read covers, so an iteration's progress runs once\n // from nothing to its last row rather than restarting at every chunk - the rule `_buildRows` follows\n // for the `rows` stage, and what `iterate()` documents. A call that covers the whole read passes\n // neither and counts its own rows.\n const decodedBefore = progressBase;\n const decodedTotal = progressTotal === null ? rowsToLoad : progressTotal;\n\n // Every read parses the symbols before it decodes a row. The count checked against is the\n // parsed one, which still counts a symbol the two-pass path skipped: the parser keeps its place.\n assert(this._symbolTable, 'The QVD file symbol table has not been parsed.');\n const symbolTable = this._symbolTable;\n\n const decoders = fields.map((/** @type {any} */ field, /** @type {number} */ position) => ({\n bitOffset: headerInteger(field['BitOffset']),\n bitWidth: headerInteger(field['BitWidth']),\n bias: headerInteger(field['Bias']),\n symbolCount: symbolTable[position].numbers.length,\n name: field['FieldName'],\n }));\n // One array of codes per field. An iteration hands in the arrays it made for its first chunk and they\n // serve every chunk after it - the same size every time, and nothing keeps a chunk's codes once its\n // rows are built, since `_buildRows` copies the values out and the frame it yields holds only those.\n // A read that keeps its codes - `loadColumnar`, whose table is handed them - hands in nothing and gets\n // arrays of its own, which no later read can write over.\n const columns =\n into === null ? fields.map(() => new Int32Array(rowsToLoad)) : into.map((codes) => codes.subarray(0, rowsToLoad));\n\n // A slice of records at a time, every field decoded from it before the next is read, so the records\n // are read once however many fields there are. A damaged index is refused naming its file row, as\n // before, and the first refused is the first in the first slice that holds one, in field order\n // within the slice. A window whose records fit one slice - 16 MiB of them - reports exactly what it\n // did when each field was decoded in full before the next.\n await this._forEachSlice(firstRow, rowsToLoad, recordSize, (records, done, count) => {\n decoders.forEach((decoder, position) => {\n decodeIndexColumn(\n records,\n recordSize,\n count,\n decoder.bitOffset,\n decoder.bitWidth,\n decoder.bias,\n columns[position].subarray(done, done + count),\n {symbolCount: decoder.symbolCount, field: decoder.name, file: this._path, firstRow: firstRow + done},\n );\n });\n\n // Rows decoded, over the rows the read covers - a field at a time is no longer the unit of work.\n this._emitProgress('index-table', decodedBefore + done + count, decodedTotal);\n });\n\n if (rowsToLoad === 0) {\n this._emitProgress('index-table', decodedBefore, decodedTotal);\n }\n\n // Set together, once every column has decoded, so a chunk refused part-way leaves the reader\n // describing the chunk before it rather than a mix of the two.\n this._indexColumns = columns;\n this._rowsDecoded = rowsToLoad;\n }\n\n /**\n * Reads the file's schema and header metadata, without touching the symbol or index tables.\n *\n * Constant cost in the size of the file. `fromQvd(path, {maxRows: 0})` is not the same thing\n * and never was: the lazy path reads `headerEnd + symbolTableLength + rowsToLoad * recordSize`\n * bytes, so it still pulls the entire symbol table - 0.4MB on the taxi fixture, but hundreds\n * of megabytes on a high-cardinality file, and it has to be parsed as well as read.\n *\n * The memory check is deliberately not run for this. It sizes the rows a call will\n * materialise, and this materialises none; applying it would let a file too large to load\n * refuse to say what is in it.\n *\n * @return {Promise<import('./QvdDataFrame.js').QvdFileMetadata>} The file's schema and header.\n */\n async loadMetadata() {\n // A read like any other on this reader, one at a time: it parses the header into the state a read of\n // rows is using. It closes its own file before `_readData` returns, so `_closingAfter` has none to close.\n //\n // Deliberately without the checks `parseHeaderOnly` makes. `readMetadata()` describes a damaged file's\n // schema rather than refusing it - that is what it is for, and what the documentation promises - so\n // the two header reads differ in exactly that, and share what they build from the result.\n return await this._closingAfter(async () => {\n await this._readData({offset: 0, limit: null}, true);\n\n this._emitProgress('header', 0, 1);\n await this._parseHeader();\n this._emitProgress('header', 1, 1);\n this._throwIfAborted();\n\n return this.describeParsed();\n });\n }\n\n /**\n * The schema and header of the file this reader has parsed, as `readMetadata()` reports them.\n *\n * Built from the parsed header and nothing else, so a caller holding a header - a `QvdFile` - can have\n * it without reading the file a second time.\n *\n * @return {any} The metadata.\n */\n describeParsed() {\n assert(this._header && this._allFields, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n\n // The fields `_parseHeader` checked, which are the fields a read of rows reads: a header that\n // declares none, or a field with no name or another's, never gets this far.\n const columns = this._allFields.map((/** @type {any} */ field) => field['FieldName']);\n const rowCount = headerInteger(header['NoOfRecords']);\n\n // The same rule a load applies, through the same function. Coercing an unusable value to\n // zero here instead would report a damaged 606-row file as empty, and `rowCount` is exactly\n // what a caller is expected to branch on.\n validateRecordCount(rowCount, this._path, 'readMetadata');\n\n // An empty frame carrying the same header, so the camelCase mappings live in one place\n // rather than being spelled out a second time here and drifting from the ones a loaded\n // frame reports.\n const shape = new QvdDataFrame([], columns, header, {\n symbolTableBytes: headerInteger(header['Offset']),\n totalRows: rowCount,\n rowsLoaded: 0,\n symbolFiltering: false,\n symbolsKept: null,\n });\n\n return {\n columns,\n rowCount,\n columnCount: columns.length,\n fields: columns.map((/** @type {string} */ name) => shape.getFieldMetadata(name)),\n fileMetadata: shape.fileMetadata,\n metadata: header,\n };\n }\n\n /**\n * What a read of this file would cost, and whether it fits, without reading it.\n *\n * Reads the header and the file's size and nothing else, at the constant cost of `loadMetadata()`,\n * then asks the same question a read asks before it allocates anything - through the same function,\n * from the same numbers. That is the whole point: an answer computed a second way would be a second\n * opinion, and a read this approves would still be refused.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} [rawWindow]\n * The rows the read would cover, spelled any of the ways a read accepts.\n * @param {{chunkSize?: number|null}} [options] `chunkSize` when the read would be an `iterate()`,\n * which holds two chunks of rows rather than the window.\n * @return {Promise<any>} The answer - see `checkMemory`.\n */\n async checkRead(rawWindow, {chunkSize = null} = {}) {\n // Through the same function a read normalises its window with, so that a window this approves is\n // the window the read then resolves - and so that a malformed one is refused here with the message\n // it would be refused with there.\n const window = normaliseWindow(rawWindow, this._path);\n\n return await this._closingAfter(async () => {\n await this._parseHeaderChecked();\n\n return this.checkParsed(window, {chunkSize});\n });\n }\n\n /**\n * Reads this file's header, and nothing else, leaving it parsed on the reader.\n *\n * What `checkRead` and `QvdFile` both start with: the second asks many questions of one header, so the\n * read that produces it is separate from the questions. Every check a read makes before it trusts the\n * header's numbers is made here, so that nothing downstream has to wonder whether they hold.\n *\n * @return {Promise<void>} When the header is parsed and checked.\n */\n async parseHeaderOnly() {\n return await this._closingAfter(async () => await this._parseHeaderChecked());\n }\n\n /**\n * `parseHeaderOnly`'s body, for a caller already inside a read session - `checkRead` is one.\n *\n * @return {Promise<void>} When the header is parsed and checked.\n * @private\n */\n async _parseHeaderChecked() {\n await this._readData({offset: 0, limit: null}, true);\n\n // Bracketed as `loadMetadata` brackets it, so every entry point that reads only the header reports\n // the same stages to the same `onProgress`.\n this._emitProgress('header', 0, 1);\n await this._parseHeader();\n this._emitProgress('header', 1, 1);\n this._throwIfAborted();\n\n assert(\n this._header && this._selectedFields && this._allFields && this._symbolTableOffset !== null,\n 'The QVD file header has not been parsed.',\n );\n\n const header = this._header['QvdTableHeader'];\n const totalRows = headerInteger(header['NoOfRecords']);\n const recordSize = headerInteger(header['RecordByteSize']);\n const symbolTableLength = headerInteger(header['Offset']);\n\n // Before any arithmetic, the checks a read makes before it trusts these numbers - through the same\n // functions, so the same file is refused with the same message here as there.\n //\n // Without them a check answered a memory question about a file whose real problem is structural, and\n // answered it wrongly in both directions. A `NoOfRecords` of `606.5` or `6e2` made every figure\n // `NaN`, and `NaN` loses every comparison, so the answer came back `fits: true` for a read the\n // library then refused as corrupt - the false approval this whole API exists to rule out. A header\n // claiming 900 million rows in a 29 KB file came back `fits: false, reason: 'memory'` with a\n // 122 GB estimate and advice to read 25 million rows, and following that advice was refused as\n // corrupt too.\n validateRecordSize(recordSize, this._path, 'checkRead');\n validateRecordCount(totalRows, this._path, 'checkRead');\n\n // The header against the file on disk, which is what `_headerMatchesFile` records - set by the\n // header-only read for this reason. A read makes no memory claim about a file it does not\n // describe, and neither does this: the message is the one a windowed read gives for it.\n if (!this._headerMatchesFile) {\n throw new QvdCorruptedError('The file is shorter than its header claims.', {\n file: this._path,\n fileSize: this._fileSize,\n requiredBytes: this._symbolTableOffset + symbolTableLength + totalRows * recordSize,\n stage: 'checkRead',\n });\n }\n\n // And the field metadata, through the three functions the read uses on it. All of them read header\n // numbers and nothing else, so a check that stops at the header can still make every one of them -\n // and a check that skipped them approved four kinds of damage the read refuses: a field area past\n // the end of the symbol table, two fields claiming one area, a `Bias` that is neither 0 nor -2, and\n // a `BitWidth` past 31. Every one came back `fits: true` and was then a `QvdCorruptedError`.\n //\n // Every field, selected or not, for the reason the read gives: a projection must not turn a file a\n // full read refuses into one it accepts, and answering \"this fits\" about a file that does not\n // decode is the same mistake one step earlier.\n const tableLength = this._symbolTableLength();\n\n for (const field of this._allFields) {\n validateFieldMetadata(field, tableLength, this._path);\n validateFieldBitMetadata(field, recordSize, this._path);\n }\n\n validateSymbolAreas(this._allFields, this._path);\n }\n\n /**\n * What a read of the parsed header's file would cost, with no I/O at all.\n *\n * Separate from `checkRead` because a `QvdFile` asks this of one header many times - once per page a\n * viewer scrolls to - and the header is already in hand. `parseHeaderOnly` has to have run.\n *\n * @param {QvdRowWindow} window The rows the read would cover, normalised.\n * @param {{chunkSize?: number|null, fields?: Array<string>|null, materialisesRows?: boolean,\n * paging?: boolean}} [options] `chunkSize` for an `iterate()`; `fields` and `materialisesRows` to ask\n * about a read other than the one this reader was built for, which is what a `QvdFile` does per call;\n * `paging` to say whether the read being asked about is a paging read, which defaults to whether this\n * reader is one.\n * @return {any} The answer - see `checkMemory`.\n */\n checkParsed(\n window,\n {chunkSize = null, fields = undefined, materialisesRows = undefined, paging = this._symbolCache !== null} = {},\n ) {\n assert(this._header && this._allFields, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n const totalRows = headerInteger(header['NoOfRecords']);\n const recordSize = headerInteger(header['RecordByteSize']);\n const symbolTableLength = headerInteger(header['Offset']);\n const builds = materialisesRows === undefined ? this._materialisesRows : materialisesRows;\n\n // The caller's fields when it named some, this reader's otherwise. Selected here rather than taken\n // from `_selectedFields` so that one open file can be asked about different projections.\n const selected = selectFields(this._allFields, fields === undefined ? this._requestedFields : fields, this._path);\n\n const resolved = resolveWindow(window, totalRows);\n\n // The rows the read would really cover, which is what `_readFrom` hands the guard. Passing `null`\n // for a window with no `limit` ignored its `offset`, so `{offset: 600}` on a 606-row file was\n // sized as all 606 - the same read, estimated two different ways by the two halves that must agree.\n const windowRows = resolved.limit;\n const liveRows = chunkSize === null ? null : {rows: chunkSize * 2, perChunk: 2};\n // Whether the read being asked about pages, which is not always whether this reader does. A `QvdFile`'s\n // header reader has paging on, so that a check made before the first page is priced as the page will\n // be - but it is also what answers a question about an `iterate()` of the file, which is a fresh reader\n // with paging off: two-pass filtering where the window wants it, no whole-column charge, nothing held\n // over from earlier reads. Reading the mode off the reader priced that iterate as a page (#301).\n //\n // Decided by `paging` alone, not by consulting this reader's cache on the way. A paging read never\n // takes the pass - a column decoded in part is a column it cannot keep - so `paging: true` means no\n // pass whatever mode this reader is in. Reading it through `_analysisAhead` instead let the reader's\n // own cache decide: `paging: true` on a reader that does not page turned the pass back on and\n // charged a record pass a paging read never makes.\n const analysisAhead = paging ? false : this._analysisWouldRun(window, resolved, totalRows, symbolTableLength);\n\n // One measurement for every question asked below, the answer and each candidate selection alike.\n // Measured per call, each suggestion was sized against a slightly different budget from the answer\n // that prompted it, and a wide file paid for a heap-statistics call per column.\n const measured = getMemoryBudget();\n\n const ask = (/** @type {any} */ asked, /** @type {number|null} */ rows) => {\n // A read that does not page holds and reads exactly what it selects: nothing cached to add, and\n // nothing cached to skip.\n const held = paging ? this._fieldsHeldAfter(asked, this._allFields) : asked;\n const bytes = symbolBytesOf(held, symbolTableLength);\n const read = symbolBytesOf(paging ? this._fieldsReadBy(asked) : asked, symbolTableLength);\n const retained = paging ? symbolBytesOf(held.slice(asked.length), symbolTableLength) : 0;\n\n return checkMemory({\n measured,\n symbolTableSize: bytes,\n maxRows: rows,\n totalRows,\n safetyFactor: this._memorySafetyFactor,\n columnCount: asked.length,\n materialisesRows: builds,\n live: liveRows,\n // A paging read keeps whole columns, so it is charged for whole columns - see `estimateMemoryUsage`.\n wholeSymbols: paging,\n retainedBytes: retained,\n bytesHeld: this._bytesHeld(read, rows, recordSize, liveRows, analysisAhead, bytes - retained),\n // What it reads from the file, which is not what it holds: the symbol areas it has still to read,\n // and every record the window covers, read a slice at a time and not kept - twice over where the\n // symbol-usage pass will run, since it reads them before the decode reads them again.\n readBytes: read + readPasses(analysisAhead) * windowRows * recordSize,\n });\n };\n\n const answer = ask(selected, windowRows);\n\n // The one suggestion `checkMemory` cannot make for itself: it is given what the selection costs\n // and never what each field costs. Offered only when dropping fields is something the caller can\n // actually do - more than one selected - and only after the smaller selection has been read back\n // through the check, like every other suggestion here.\n if (!answer.fits && selected.length > 1) {\n const bySize = [...selected].sort(\n (/** @type {any} */ a, /** @type {any} */ b) => headerInteger(a['Length']) - headerInteger(b['Length']),\n );\n\n for (let take = selected.length - 1; take >= 1; take -= 1) {\n const fewer = bySize.slice(0, take);\n\n if (ask(fewer, windowRows).fits) {\n answer.suggestions.push({\n option: 'fields',\n value: fewer.map((/** @type {any} */ field) => field['FieldName']),\n });\n break;\n }\n }\n }\n\n return answer;\n }\n\n /**\n * Loads the QVD file into memory and parses it.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} [window]\n * The rows to load. A number or null means what it always meant - the first N rows, or all of\n * them - and `{offset, limit}` is the same thing said more precisely, so `5` and\n * `{offset: 0, limit: 5}` are one read. `maxRows` is accepted as a second name for `limit`.\n * @throws {QvdValidationError} If the window is not a non-negative integer, null, or a valid\n * `{offset, limit}` object.\n * @return {Promise<QvdDataFrame>} The loaded QVD file.\n */\n async load(window = null) {\n const rows = normaliseWindow(window, this._path);\n\n return await this._closingAfter(async () => {\n const prepared = await this._prepare(rows);\n\n await this._parseIndexTable({offset: prepared.offset, limit: prepared.rowsAvailable});\n\n const data = this._buildRows(prepared.resolvedByField, 0, prepared.rowsAvailable);\n\n return new QvdDataFrame(\n data,\n prepared.columns,\n prepared.metadata,\n {\n ...prepared.loadStats,\n rowsLoaded: data.length,\n },\n prepared.storedSymbols,\n );\n });\n }\n\n /**\n * Reads the file as columns, without ever materialising rows.\n *\n * Shares every step with `load()` up to the point where rows would be built - see `_prepare`.\n * What it keeps instead is what the decoder already produced: one `Int32Array` of stored\n * indices per field, and one resolved value per distinct symbol. On the 1.7M x 20 taxi\n * fixture that is 133 MiB against the 352 MiB `data` retains, because a column costs four\n * bytes per row rather than a boxed value per cell, and the symbols are a few thousand\n * entries shared across every row that uses them. The codes' storage lives outside the V8\n * heap: 3 MiB of the 133 is on it.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} [window]\n * The rows to decode, in the same spellings `load()` accepts.\n * @return {Promise<import('./QvdColumnTable.js').QvdColumnTable>} The decoded columns.\n */\n async loadColumnar(window = null) {\n const rows = normaliseWindow(window, this._path);\n\n return await this._closingAfter(async () => {\n const prepared = await this._prepare(rows, null, true);\n\n await this._parseIndexTable({offset: prepared.offset, limit: prepared.rowsAvailable});\n\n // The table is built inside the read, not after it. `_closingAfter` lets the next read start the\n // moment it returns, and the import below is an `await`: a read beginning in that gap would decode\n // over `_indexColumns` and `_rowsDecoded` before this table had copied them, and the table would\n // carry this read's symbols and metadata with the other read's codes - the wrong values, thrown by\n // nothing. The file is closed once this returns; the table holds no part of it.\n const {QvdColumnTable} = await import('./QvdColumnTable.js');\n\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n return new QvdColumnTable({\n columns: prepared.columns,\n codesByField: this._indexColumns,\n symbolsByField: prepared.resolvedByField,\n halvesByField: prepared.halvesByField,\n rowCount: this._rowsDecoded,\n metadata: prepared.metadata,\n storedSymbols: prepared.storedSymbols,\n loadStats: {...prepared.loadStats, rowsLoaded: this._rowsDecoded},\n });\n });\n }\n\n /**\n * Yields the window as data frames of at most `chunkSize` rows.\n *\n * The file is opened, read and parsed **once**; only the index decode and the row building\n * happen per chunk. That is the whole reason this exists as a method rather than as a loop of\n * `load({offset, limit})` calls at the call site: the symbol table has to be parsed in full\n * whatever the chunk size - a stored index in the last chunk can address the first symbol -\n * and re-parsing it per chunk is what makes the obvious implementation cost more than a plain\n * load rather than less. PyQvd's chunked read does re-read it, and the comment on #140 records\n * that as a limitation rather than a design.\n *\n * What it bounds is row materialisation, which is what actually dominates a large read's heap.\n * Two chunks of rows are alive at a time, not one - `for await` keeps the yielded frame\n * reachable while this generator builds the next - which is why `liveRows` below is\n * `chunkSize * 2`, and why the heap it needs is twice what one chunk suggests.\n *\n * A window covering no rows yields nothing at all, rather than one empty frame - so\n * `for await` over an exhausted offset does nothing, which is what a paging loop wants. Its header\n * is still checked, as every read of a file's rows checks it.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} window\n * The rows to cover, in the same spellings `load()` accepts.\n * @param {number} chunkSize Rows per frame. Must be a positive integer.\n * @return {AsyncGenerator<QvdDataFrame>} The chunks, in order.\n */\n async *iterateRows(window, chunkSize) {\n requireChunkSize(chunkSize, this._path);\n\n // The memory guard sizes what is live at once, and from here that is *two* chunks rather than\n // the whole window. Passed into `_prepare` rather than stored on the reader, so it cannot\n // outlive this call: while it was an instance field, a reader used for `load()` after an\n // iteration would have the guard size two chunks for a read that materialises every row -\n // failing open, which is the uncatchable direction. No caller could reach that today, but\n // nothing said the reader was single-use either, and `QvdFileReader` is a documented export.\n // It is paired with the chunk size it came from so a refusal can recommend a chunk size rather\n // than a live-row count the caller has no knob for.\n //\n // Two, not one, because `for await (const chunk of ...)` keeps the yielded frame reachable\n // while the generator computes the next one - that is the async-iteration protocol, not\n // something this code can arrange away. Charging one chunk was measured and it was wrong in\n // the dangerous direction: on the 1.7M x 20 taxi fixture with `chunkSize: 500_000`, a read\n // that needs a 214MB heap was admitted at 170MB and the process aborted with a V8 heap-limit\n // abort - uncatchable, which is the exact failure the guard exists to prevent. Against the\n // measured minimum heap at four chunk sizes the two-chunk figure sits at 1.00 to 1.14x, never\n // below; the one-chunk figure sat at 0.53 to 0.61x.\n //\n // `estimateMemoryUsage` caps this at the window, so a window smaller than two chunks is still\n // charged only for itself.\n const liveRows = {rows: chunkSize * 2, perChunk: 2};\n\n const rows = normaliseWindow(window, this._path);\n\n // The file stays open from the first chunk to the last: each chunk's records are read when that\n // chunk is built, not all of them up front. It is closed however the iteration ends - after the\n // last chunk, when the caller stops early (`break` in a `for await` calls `return()`, which runs\n // the `finally`), or when a chunk is refused - with `_closeFile`'s rule that a failing close never\n // replaces the error already thrown. The read starts on the first `next()`, which runs this far\n // before it awaits anything, so a read started beside it is refused however soon it follows.\n this._startRead();\n\n let failing = false;\n\n try {\n const prepared = await this._prepare(rows, liveRows);\n\n // A window of no rows yields nothing, but the header is checked all the same. `load()` checks it\n // for `{limit: 0}`, because it plans an empty index table, and so does the two-pass path. The loop\n // below never runs for such a window, so it used to be the one read of a file's rows that let a\n // header every other read refuses - a Bias out of range, a BitWidth past 31 - go by unchecked.\n if (prepared.rowsAvailable === 0) {\n this._planIndexTable({offset: prepared.offset, limit: 0}, 'parseIndexTable');\n return;\n }\n\n // The codes of one chunk, made once and written over by every chunk after it. A chunk's rows are\n // built from them before the next chunk decodes, and the frame that is yielded holds the rows, so\n // nothing outlives the chunk it belongs to. Made here rather than per chunk because an iteration of\n // 83 million rows in chunks of 100,000 over twenty fields would otherwise make 830 sets of them, 8 MB\n // at a time, for buffers that never change size.\n const codes = prepared.columns.map(() => new Int32Array(Math.min(chunkSize, prepared.rowsAvailable)));\n\n for (let done = 0; done < prepared.rowsAvailable; done += chunkSize) {\n this._throwIfAborted();\n\n const count = Math.min(chunkSize, prepared.rowsAvailable - done);\n const offset = prepared.offset + done;\n\n await this._parseIndexTable({offset, limit: count}, done, prepared.rowsAvailable, codes);\n\n const data = this._buildRows(prepared.resolvedByField, done, prepared.rowsAvailable);\n\n // Every chunk shares the one record: the symbol table was parsed once, in full, for all of them.\n yield new QvdDataFrame(\n data,\n prepared.columns,\n prepared.metadata,\n {\n ...prepared.loadStats,\n offset,\n rowsLoaded: data.length,\n },\n prepared.storedSymbols,\n );\n }\n } catch (error) {\n failing = true;\n throw error;\n } finally {\n await this._endRead(failing);\n }\n }\n\n /**\n * Reads the file and resolves its symbols, stopping short of decoding any rows.\n *\n * Everything `load()`, `loadColumnar()` and `iterateRows()` have in common, which is everything\n * that depends on the file rather than on the window. Two read paths for one binary format is\n * the drift risk #113 is the standing example of - a stored index resolved one way here and\n * another way there returns plausible wrong values and throws nothing - so there is one path,\n * and the entry points differ only in what they do with what it returns and how many rows they\n * ask for at a time.\n *\n * @param {QvdRowWindow} window The rows the read covers.\n * @param {{rows: number, perChunk: number}|null} [liveRows] Rows held at one instant when that\n * is fewer than the window covers, and how many of them one row of the caller's chunk size\n * accounts for. Only `iterateRows` passes it; every other read holds what it covers.\n * @param {boolean} [wantHalves=false] Whether to keep both halves of each symbol of a field whose\n * cells do not show them, which only a columnar read has a use for.\n * @return {Promise<{columns: Array<string>, metadata: any, loadStats: any,\n * resolvedByField: Array<Array<any>>,\n * halvesByField: Array<import('./util/resolveSymbols.js').SymbolHalves|null>,\n * storedSymbols: import('./util/storedSymbols.js').StoredSymbols|null,\n * rowsAvailable: number, offset: number}>} The parsed file, with the window as it resolved\n * against it.\n * @private\n */\n async _prepare(window, liveRows = null, wantHalves = false) {\n this._throwIfAborted();\n\n await this._readData(window, false, liveRows);\n\n this._emitProgress('header', 0, 1);\n await this._parseHeader();\n this._emitProgress('header', 1, 1);\n this._throwIfAborted();\n\n assert(this._header, 'The QVD file header has not been parsed.');\n\n const totalRows = headerInteger(this._header['QvdTableHeader']['NoOfRecords']);\n const symbolTableLength = headerInteger(this._header['QvdTableHeader']['Offset']);\n\n // Where this window lands in this file. Resolved through the same function `_readData` used,\n // so the rows that were read and the rows that will be decoded cannot disagree.\n const resolved = resolveWindow(window, totalRows);\n const rowsAvailable = resolved.limit;\n\n // Determine if we should use two-pass symbol filtering\n // This optimization is beneficial for large symbol tables with limited row access\n let symbolsToKeep = null;\n let symbolsKept = null;\n\n // Which reads take the pass, and why, is in `_analysisWouldRun`. Asked through it rather than stated\n // here, because `_readData` has to ask the same question before the header is parsed to know what to\n // charge the memory guard, and one condition asked twice is one that drifts.\n // Never while paging: the pass decodes only what a window's rows use, and a cache of part of a\n // field is a cache that answers `undefined` for a row a later page asks about.\n if (this._analysisAhead(window, resolved, totalRows, symbolTableLength)) {\n // Pass 1: Analyze which symbols are actually needed\n symbolsToKeep = await this._analyzeIndexTableSymbolUsage({offset: resolved.offset, limit: rowsAvailable});\n\n // Recorded rather than logged. This used to be a console.log, which a library has no\n // business emitting: callers could not silence it, and it was the only way to find out\n // whether filtering had happened. It is now reported through QvdDataFrame.loadStats,\n // which callers can inspect - and tests can assert on deterministically, where the\n // previous test measured a heapUsed delta and failed on GC timing instead.\n symbolsKept = symbolsToKeep.reduce((sum, set) => sum + set.size, 0);\n }\n\n // Pass 2: Parse symbol table (with filtering if enabled)\n await this._parseSymbolTable(symbolsToKeep, rowsAvailable, liveRows);\n\n assert(this._symbolTable, 'The QVD file symbol table has not been parsed.');\n this._throwIfAborted();\n\n assert(this._selectedFields, 'The QVD file fields have not been resolved.');\n\n // Resolve each field's symbols once rather than once per cell.\n //\n // A stored index addresses the same symbol in every row, so what it reads as depends only on the\n // index. Doing it inside the row loop repeated it 34 million times on the taxi fixture for a\n // symbol table of a few thousand entries.\n //\n // A symbol the two-pass path did not decode has neither half and resolves to undefined here, and\n // no row of the window holds it. An index past the end of the array cannot reach this far: the\n // decode refuses it (#125), where it used to read as undefined too.\n //\n // A dual used to resolve to its text alone, so its number was unreachable and a write stored the\n // date as a string (#138). What it resolves to now depends on the `duals` option, and the half a\n // cell does not show goes into the stored-symbol record, which is what a write reads it back from.\n /** @type {Array<Array<any>>} */\n const resolvedByField = [];\n /** @type {Array<import('./util/resolveSymbols.js').SymbolHalves|null>} */\n const halvesByField = [];\n /** @type {Array<import('./util/storedSymbols.js').StoredSymbolsEntry>} */\n const entries = [];\n\n this._symbolTable.forEach((symbols, position) => {\n const {values, entry, halves} = resolveFieldSymbols(\n symbols,\n // @ts-ignore - asserted above\n this._selectedFields[position]['FieldName'],\n this._duals,\n this._coerceNumericStrings,\n wantHalves,\n );\n\n resolvedByField.push(values);\n halvesByField.push(halves);\n\n if (entry !== null) {\n entries.push(entry);\n }\n });\n\n const columns = this._selectedFields.map((/** @type {any} */ field) => field['FieldName']);\n\n // The complete header metadata, describing the *file* rather than this read of it.\n //\n // Not narrowed to the selected fields, and not adjusted for the window. `NoOfRecords` has\n // always been the file's row count rather than the number loaded - that is what `loadStats`\n // is for - and `select()` has always passed the whole header through to the frame it returns,\n // so narrowing here would give one answer for a projection made at load time and another for\n // the same projection made afterwards.\n const metadata = this._header['QvdTableHeader'];\n\n // Null rather than an empty record when every cell shows its whole symbol, which is the common case\n // for a file without duals. The record is also left on the header object, not enumerably, so a frame\n // built as `new QvdDataFrame(data, columns, df.metadata)` keeps it.\n const storedSymbols = entries.length > 0 ? trustStoredSymbols(entries) : null;\n\n if (storedSymbols !== null) {\n attachStoredSymbols(metadata, storedSymbols);\n }\n\n /** @type {import('./QvdDataFrame.js').QvdLoadStats} */\n const loadStats = {\n symbolTableBytes: symbolTableLength,\n totalRows,\n rowsLoaded: 0,\n offset: resolved.offset,\n symbolFiltering: symbolsToKeep !== null,\n symbolsKept,\n };\n\n return {\n columns,\n metadata,\n loadStats,\n resolvedByField,\n halvesByField,\n storedSymbols,\n rowsAvailable,\n offset: resolved.offset,\n };\n }\n\n /**\n * Builds rows from the columns currently decoded.\n *\n * `data` stays eager: of the four ways this library is used - a full read, a preview already\n * bounded by a limit, writing an array out, and reading metadata - not one is helped by\n * materialising a row only when it is touched, and a lazy accessor would cost a proxy, a cache\n * and mutation semantics to serve none of them. A caller who wants columns without paying for\n * rows uses `QvdColumnTable`, which stops before this loop.\n *\n * @param {Array<Array<any>>} resolvedByField One resolved value per distinct symbol, per field.\n * @param {number} progressBase Rows already delivered before this call, so that progress over a\n * chunked iteration counts the whole window rather than restarting at every chunk.\n * @param {number} progressTotal Rows the whole window covers.\n * @return {Array<Array<any>>} The rows.\n * @private\n */\n _buildRows(resolvedByField, progressBase, progressTotal) {\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n const indexColumns = this._indexColumns;\n const fieldCount = indexColumns.length;\n const rowCount = this._rowsDecoded;\n const data = new Array(rowCount);\n\n // Report about once per percent of the window, as the writer does, and at least once at the\n // end. Checking the abort signal on the same tick keeps a cancelled 20-million-row load from\n // running to completion before it notices.\n const reportInterval = Math.max(1, Math.floor(progressTotal / 100));\n\n for (let row = 0; row < rowCount; row++) {\n const values = new Array(fieldCount);\n\n for (let field = 0; field < fieldCount; field++) {\n const symbolIndex = indexColumns[field][row];\n\n // A negative index is how a bias of -2 encodes NULL: stored index 0 means NULL, and\n // real symbols start at 2. It addresses no symbol. The decode has refused every other\n // index that addresses nothing, so a non-negative one is always inside the array.\n values[field] = symbolIndex < 0 ? null : resolvedByField[field][symbolIndex];\n }\n\n data[row] = values;\n\n if ((progressBase + row + 1) % reportInterval === 0 || row + 1 === rowCount) {\n this._throwIfAborted();\n this._emitProgress('rows', progressBase + row + 1, progressTotal);\n }\n }\n\n return data;\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {normaliseWindow, readerOptionsFrom, requireChunkSize, windowFrom} from './util/readOptions.js';\n\n/**\n * A QVD file opened for paging: its header read once, and read from a page at a time.\n *\n * Every other entry point is one read from start to finish - open the file, read the header, parse the\n * symbols it needs, build the result, close. A viewer showing a hundred rows at a time pays the header\n * and the symbol parse again on every page, and `iterate()` is no answer either: it goes forwards only,\n * so it cannot jump to row five million and it cannot go back.\n *\n * ```js\n * const qvd = await QvdDataFrame.open('sales.qvd', {allowedDir: '/data'});\n *\n * qvd.metadata; // read once, when it opened\n * const answer = qvd.check({offset: 0, limit: 100}); // no I/O at all: the header is already here\n * const page = await qvd.rows({offset: 5_000_000, limit: 100});\n *\n * await qvd.close();\n * ```\n *\n * The header is read once, and so is each column: a column decoded for one page is kept for the pages\n * after it, and neither its bytes nor its values are read again. On a 300,000-row file with a\n * 50,000-value text column, pages settled at about 2 ms against about 13 ms for the same window through\n * `fromQvd()`. The first page costs about what a single read costs; it is the ones after it that are\n * cheap.\n *\n * Each page still opens the file, and a first touch still decodes a whole column rather than only as\n * far as the page needs - see the issue for both.\n *\n * Calls are serialised, in the order they were made, so a viewer can ask for the next page without\n * awaiting the one before it. That is this class's job rather than the reader's: a `QvdFileReader`\n * refuses a second read while one is under way, and serialising here means it never sees two.\n */\nexport class QvdFile {\n /**\n * Not called directly - `QvdDataFrame.open()` is the way in, because a `QvdFile` is only ever a file\n * whose header has been read, and a constructor cannot wait for that.\n *\n * @param {any} reader The reader holding the parsed header.\n * @param {any} metadata What `readMetadata()` returns for this file.\n * @param {any} options The options the file was opened with.\n * @private\n */\n constructor(reader, metadata, options) {\n this._reader = reader;\n this._metadata = metadata;\n this._options = options;\n this._closed = false;\n\n /**\n * The tail of the queue: every call chains onto it, so they run one at a time and in order.\n *\n * It absorbs failures - `.then(ignore, ignore)` - because a page that throws must not stop the pages\n * behind it. A viewer that asks for a row past the end of the file should get that one refusal, not\n * a dead file.\n */\n this._tail = Promise.resolve();\n\n /**\n * The readers the pages go through, one per shape, each keeping what it has decoded.\n *\n * Built on the first page of that shape rather than at `open()`, because a file may only ever be\n * asked for rows, or only for columns, and a reader that decodes nothing is a reader nobody needed.\n */\n this._readers = {rows: null, columns: null};\n }\n\n /**\n * The file's header and schema, as `QvdDataFrame.readMetadata()` returns them.\n *\n * Read when the file was opened, so this costs nothing and cannot fail.\n *\n * @return {any} The metadata.\n */\n get metadata() {\n return this._metadata;\n }\n\n /**\n * Whether `close()` has been called.\n *\n * @return {boolean} True once it has.\n */\n get closed() {\n return this._closed;\n }\n\n /**\n * What a read of this file would cost, and whether it fits - with no I/O at all.\n *\n * Without `chunkSize` it asks about a page, and answers for the page this file would read next: the\n * columns it names plus the ones earlier pages decoded and kept, since those are part of what the page\n * costs. With `chunkSize` it asks about an `iterate()` of the file instead - which this object cannot\n * make, but a caller holding it may want to weigh - and answers exactly as `QvdDataFrame.checkRead()`\n * would, from the header this file already holds rather than by reading it again.\n *\n * @param {{offset?: number, limit?: number|null, maxRows?: number|null, fields?: Array<string>|null,\n * as?: 'rows'|'columns', chunkSize?: number|null}} [options] The read being asked about - the same\n * bag `rows()` takes, plus `as` to say which shape of page, and `chunkSize` to ask about an\n * `iterate()` of the file rather than a page.\n * @return {any} The answer - `fits`, `reason`, `estimate`, `budget`, `exact`, `suggestions`.\n * @throws {QvdValidationError} If the file is closed, or an option's value is not valid.\n */\n check(options = {}) {\n this._refuseWhenClosed('check');\n\n const {as = 'rows', chunkSize = null} = options;\n\n if (as !== 'rows' && as !== 'columns') {\n throw new QvdValidationError(\"as must be 'rows' or 'columns'\", {\n provided: as,\n reason: 'option',\n option: 'as',\n value: as,\n file: this._options.path,\n });\n }\n\n if (chunkSize !== null) {\n requireChunkSize(chunkSize, this._options.path);\n }\n\n // A question about a page is asked of the reader that would make it, not of the one holding the\n // header: once a page of this shape has been read, that reader is holding decoded columns, and they\n // are part of what the next page costs. Asked of the header reader, a warm file answered as though it\n // were cold - the check and the read disagreeing about the same page, which is the one thing this\n // answer must not do. Before any page of that shape there is no such reader, and the header reader\n // is the right one.\n //\n // A question naming `chunkSize` is not about a page. It asks what an `iterate()` of this file would\n // cost, and an `iterate()` is a fresh reader with nothing cached - so it goes to the header reader,\n // which holds no pages' columns, and is asked as a read that does not page (below). Asked of the paging\n // reader it was priced against columns that read would not be holding: on a four-column file after a\n // page had decoded all four, 29.6 MB where `checkRead` says 19.5 MB, and a read of 0.31 MB where the\n // iterate reads 0.87 MB. That described neither the iterate it named nor the page this object can\n // make (#301).\n const reader = chunkSize !== null ? this._reader : (this._readers[as] ?? this._reader);\n\n return reader.checkParsed(normaliseWindow(windowFrom(options), this._options.path), {\n chunkSize,\n // Resolved here rather than left to the reader, exactly as `_page` resolves it. A warm reader is\n // still holding the last page's selection, and `checkParsed` falls back to it - so a `check()`\n // naming no fields answered for whatever the previous page happened to name. On a four-column\n // file after a page naming one of them, it reported 27,490 bytes for a read that costs 108,160:\n // understating, which is the direction that approves a read the read then refuses.\n fields: options.fields === undefined ? (this._options.fields ?? null) : options.fields,\n materialisesRows: as === 'rows',\n // Said outright rather than read off the reader. The header reader has paging on, because a check\n // made before the first page has to be priced as that page will be - so it cannot tell an `iterate()`\n // question from a page one by its own mode, and routing to it alone still priced the iterate as a\n // page wherever a bounded window would have been filtered.\n ...(chunkSize === null ? {} : {paging: false}),\n });\n }\n\n /**\n * Reads a page of rows.\n *\n * @param {{offset?: number, limit?: number|null, maxRows?: number|null, fields?: Array<string>|null,\n * onProgress?: Function, signal?: AbortSignal}} [options] The page, and how to read it. One bag,\n * as every other entry point takes: `offset` and `limit` say which rows, `fields` names a projection\n * for this page alone, and anything left out falls back to what the file was opened with.\n * @return {Promise<any>} The page, as a `QvdDataFrame`.\n * @throws {QvdValidationError} If the file is closed.\n */\n async rows(options = {}) {\n this._refuseWhenClosed('rows');\n\n return await this._serialised(async () => await this._page(options, true, (reader, window) => reader.load(window)));\n }\n\n /**\n * Reads a page as columns, building no rows.\n *\n * @param {{offset?: number, limit?: number|null, maxRows?: number|null, fields?: Array<string>|null,\n * onProgress?: Function, signal?: AbortSignal}} [options] The page, as `rows()` takes it.\n * @return {Promise<any>} The page, as a `QvdColumnTable`.\n * @throws {QvdValidationError} If the file is closed.\n */\n async columns(options = {}) {\n this._refuseWhenClosed('columns');\n\n return await this._serialised(\n async () => await this._page(options, false, (reader, window) => reader.loadColumnar(window)),\n );\n }\n\n /**\n * Closes the file.\n *\n * Every call after it is refused with `reason: 'closed'`. Calling it twice is not an error: a\n * `finally` that closes and an `await using` that closes are both right, and both may run.\n *\n * @return {Promise<void>} When the pages already in flight have finished.\n */\n async close() {\n if (this._closed) {\n return;\n }\n\n this._closed = true;\n\n // The pages already queued still run: they were asked for while the file was open, and a page that\n // was going to arrive should arrive. What `closed` stops is asking for another.\n await this._tail;\n\n // And then the columns they decoded go. `close()` is the caller saying they are done with the file,\n // and a closed file that still holds every column any page touched is holding the memory closing it\n // was meant to release - which on the files this exists for is gigabytes, for as long as anything\n // keeps the object.\n for (const reader of Object.values(this._readers)) {\n reader?.endPaging();\n }\n\n this._readers = {rows: null, columns: null};\n this._reader.endPaging();\n this._reader = null;\n }\n\n /**\n * `await using` support, where the runtime has it.\n *\n * @return {Promise<void>} When closed.\n */\n async [Symbol.asyncDispose]() {\n await this.close();\n }\n\n /**\n * Refuses a call on a closed file, in the vocabulary the rest of the API uses.\n *\n * @param {string} call The method the caller reached for, for the error.\n * @private\n */\n _refuseWhenClosed(call) {\n if (this._closed) {\n throw new QvdValidationError('The file is closed: open it again to read from it', {\n reason: 'closed',\n call,\n file: this._options.path,\n });\n }\n }\n\n /**\n * Runs `work` after everything asked for before it, and before everything asked for after.\n *\n * @param {() => Promise<any>} work The page to read.\n * @return {Promise<any>} Its result.\n * @private\n */\n async _serialised(work) {\n const run = this._tail.then(work, work);\n\n // Failures are absorbed from the *queue*, not from the caller: `run` is what the caller awaits and\n // still rejects, while the tail carries on so one refused page does not refuse every page behind it.\n this._tail = run.then(\n () => undefined,\n () => undefined,\n );\n\n return await run;\n }\n\n /**\n * Reads one page, through the reader that keeps what the pages before it decoded.\n *\n * One reader for every page rather than one per page, which is what makes the symbol cache possible:\n * decoding the symbols is 72% of a page of a hundred rows from a 300,000-row file, and a reader built\n * fresh each time did all of it again. Two readers, because a columnar page builds no rows and a row\n * page does, and `materialisesRows` is fixed when a reader is constructed - so each shape keeps its\n * own, and its own cache.\n *\n * Options that belong to one call rather than to the file - the fields this page alone wants, and the\n * `onProgress` and `signal` watching it - are told to that shared reader for the next read and no\n * further. A page naming one of them used to build a reader of its own instead, which quietly turned\n * the cache off and the two-pass symbol path on: watching a page changed what the page did.\n *\n * @param {any} options What the call passed.\n * @param {boolean} builds Whether the page materialises rows.\n * @param {(reader: any, window: any) => Promise<any>} read The read to make.\n * @return {Promise<any>} The page.\n * @private\n */\n async _page(options, builds, read) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const kept = builds ? 'rows' : 'columns';\n\n if (!this._readers[kept]) {\n const reader = new QvdFileReader(this._options.path, {\n ...readerOptionsFrom(this._options),\n materialisesRows: builds,\n });\n\n reader.beginPaging();\n this._readers[kept] = reader;\n }\n\n const reader = this._readers[kept];\n\n // The file's fields unless this page names its own, which is what the API proposal settled on:\n // both, with the file's as the default.\n reader.selectForNextRead(options.fields === undefined ? (this._options.fields ?? null) : options.fields);\n\n // And this page's watchers, which belong to one call. A page naming either used to get a reader of\n // its own - so passing a progress callback silently turned the cache off and the two-pass symbol\n // path on, changing what the read did rather than only observing it.\n reader.observeNextRead({\n onProgress: options.onProgress ?? this._options.onProgress,\n signal: options.signal ?? this._options.signal,\n });\n\n return await read(reader, windowFrom(options));\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {asDual, describeType, isPlainObject} from './util/cellRules.js';\nimport {metadataOptionsFrom, readerOptionsFrom, requireChunkSize, windowFrom} from './util/readOptions.js';\nimport {\n STORED_SYMBOLS,\n attachStoredSymbols,\n narrowStoredSymbols,\n normaliseStoredSymbols,\n storedSymbolsEntry,\n storedTextOf,\n} from './util/storedSymbols.js';\n\n/**\n * @typedef {Object} QvdNumberFormat\n * @property {string} Type - Number format type\n * @property {string} nDec - Number of decimals\n * @property {string} UseThou - Use thousands separator\n * @property {string} Fmt - Format string\n * @property {string} Dec - Decimal separator\n * @property {string} Thou - Thousands separator\n */\n\n/**\n * @typedef {Object} QvdFieldHeader\n * @property {string} FieldName - The name of the field\n * @property {string|number} [BitOffset] - The bit offset\n * @property {string|number} [BitWidth] - The bit width\n * @property {string|number} [Bias] - The bias value\n * @property {string|number} [NoOfSymbols] - Number of symbols\n * @property {string|number} [Offset] - The offset\n * @property {string|number} [Length] - The length\n * @property {string} [Comment] - Field comment\n * @property {QvdNumberFormat|string} [NumberFormat] - Number format\n * @property {Object|string} [Tags] - Field tags\n */\n\n/**\n * @typedef {Object} QvdFields\n * @property {QvdFieldHeader|QvdFieldHeader[]} QvdFieldHeader - Field header(s)\n */\n\n/**\n * @typedef {Object} QvdMetadata\n * @property {string|number} [QvBuildNo] - QlikView build number\n * @property {string} [CreatorDoc] - Creator document\n * @property {string} [CreateUtcTime] - Creation UTC time\n * @property {string} [SourceCreateUtcTime] - Source creation UTC time\n * @property {string} [SourceFileUtcTime] - Source file UTC time\n * @property {string|number} [SourceFileSize] - Source file size\n * @property {string} [StaleUtcTime] - Stale UTC time\n * @property {string} [TableName] - Table name\n * @property {string|number} [NoOfRecords] - Number of records\n * @property {string|number} [RecordByteSize] - Record byte size\n * @property {string|number} [Offset] - Offset\n * @property {string|number} [Length] - Length\n * @property {string} [Compression] - Compression type\n * @property {string} [Comment] - Comment\n * @property {string} [EncryptionInfo] - Encryption info\n * @property {string} [TableTags] - Table tags\n * @property {string} [ProfilingData] - Profiling data\n * @property {Object|string} [Lineage] - Lineage\n * @property {QvdFields} [Fields] - Fields information\n */\n\n/**\n * A QVD file's schema and header, read without its data.\n *\n * @typedef {Object} QvdFileMetadata\n * @property {Array<string>} columns Field names, in file order.\n * @property {number} rowCount Rows the file declares in its header. Note that this is the\n * file's row count, not a number of rows loaded - nothing was loaded.\n * @property {number} columnCount Number of fields.\n * @property {Array<Object|null>} fields Per-field metadata, in the same shape and order that\n * `getFieldMetadata()` returns for a loaded frame.\n * @property {Object} fileMetadata File-level metadata, in the same shape as the `fileMetadata`\n * accessor on a loaded frame.\n * @property {QvdMetadata} metadata The raw `QvdTableHeader`, as `metadata` gives it.\n */\n\n/**\n * Statistics describing the read that produced a data frame.\n *\n * @typedef {Object} QvdLoadStats\n * @property {number} symbolTableBytes Size of the file's symbol table, in bytes.\n * @property {number} totalRows Rows the file declares in its header.\n * @property {number} rowsLoaded Rows actually materialised.\n * @property {number} [offset] File row the first materialised row came from: zero unless the read\n * asked for a window, the window's start when it did, and under `iterate()` the chunk's own\n * position - which is the only way a chunk can say where in the file it sits. An offset past the\n * end of the file reports the clamped value, so it equals `totalRows` for a window that caught\n * no rows.\n * @property {boolean} symbolFiltering Whether the two-pass symbol-filtering path was used.\n * @property {number|null} symbolsKept Symbols retained by that path, or null when it did not run.\n */\n\n/**\n * @typedef {import('./util/storedSymbols.js').StoredSymbols} QvdStoredSymbols\n */\n\n/**\n * A data frame in a form that survives `JSON`, `structuredClone`, `postMessage` and `v8.serialize`,\n * and that `fromDict` turns back into a frame writing the same symbols.\n *\n * @typedef {Object} QvdDataFrameDict\n * @property {Array<string>} columns The columns.\n * @property {Array<Array<any>>} data The rows.\n * @property {QvdMetadata|null} [metadata] The header, or null.\n * @property {QvdStoredSymbols|null} [storedSymbols] The stored-symbol record, or null.\n */\n\n/**\n * The header entry `toQvd` writes for a field nobody has described.\n *\n * @param {string} fieldName The field.\n * @return {Object} A field header with no comment, no tags and an UNKNOWN number format.\n */\nfunction defaultFieldHeader(fieldName) {\n return {\n FieldName: fieldName,\n BitOffset: 0,\n BitWidth: 0,\n Bias: 0,\n NoOfSymbols: 0,\n Offset: 0,\n Length: 0,\n Comment: '',\n NumberFormat: {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: {},\n };\n}\n\n/**\n * The header a metadata setter starts from on a frame that has none - one built by `fromDict`, or by\n * the constructor without metadata.\n *\n * @param {Array<string>} columns The frame's columns.\n * @return {QvdMetadata} A header describing every column and nothing else.\n */\nfunction defaultHeader(columns) {\n return {\n QvBuildNo: 50667,\n CreatorDoc: '',\n CreateUtcTime: '',\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: '',\n Fields: {\n QvdFieldHeader: columns.map(defaultFieldHeader),\n },\n NoOfRecords: 0,\n RecordByteSize: 0,\n Offset: 0,\n Length: 0,\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {},\n };\n}\n\n/**\n * Represents a loaded QVD file.\n */\nexport class QvdDataFrame {\n /**\n * Represents the data frame stored inside a QVD file.\n *\n * The record is resolved once, here: the fifth argument when given, otherwise the one a read left on\n * its header object, so `new QvdDataFrame(data, columns, df.metadata)` keeps what `df` would write.\n * Either is narrowed to `columns`. An entry for a field the frame does not have describes no cell it\n * holds, and would make the frame's own `toDict()` a dictionary `fromDict` refuses - which is what a\n * header's record did for a frame built from some of a read's columns.\n *\n * @param {Array<Array<any>>} data The data of the data frame.\n * @param {Array<string>} columns The columns of the data frame.\n * @param {QvdMetadata|null} metadata The metadata from the QVD file header (optional).\n * @param {QvdLoadStats|null} loadStats Statistics about the read (optional).\n * @param {QvdStoredSymbols|null} storedSymbols What the frame's cells were read from, where a cell\n * shows only one half of its symbol (optional) - see `storedSymbols`.\n * @throws {QvdValidationError} If the record is malformed.\n */\n constructor(data, columns, metadata = null, loadStats = null, storedSymbols = null) {\n this._data = data;\n this._columns = columns;\n this._metadata = metadata;\n /** Whether `_metadata` is this frame's own to change - see `_ownMetadata`. */\n this._ownsMetadata = false;\n this._loadStats = loadStats;\n /** @type {QvdStoredSymbols|null} */\n this._storedSymbols = narrowStoredSymbols(\n normaliseStoredSymbols(\n // @ts-ignore - a symbol-keyed property the reader defines on the header object\n storedSymbols ?? (metadata !== null && typeof metadata === 'object' ? metadata[STORED_SYMBOLS] : null),\n ),\n columns,\n );\n }\n\n /**\n * Returns the data of the data frame.\n */\n get data() {\n return this._data;\n }\n\n /**\n * Returns the columns of the data frame.\n */\n get columns() {\n return this._columns;\n }\n\n /**\n * Returns the shape of the data frame.\n */\n get shape() {\n return [this._data.length, this._columns.length];\n }\n\n /**\n * Returns the complete metadata object from the QVD file header.\n * @return {Object|null} The complete metadata object or null if not available.\n */\n get metadata() {\n return this._metadata;\n }\n\n /**\n * What the frame's cells were read from, where a cell shows only one half of its symbol.\n *\n * A dual read as its number has a text the cell does not show; one read as its text has a number;\n * a string read as a number has the text it was spelled with. The record keeps those halves, per\n * field, keyed by the value the cell holds, so `toQvd` writes the symbols the frame was read from\n * and `textAt` can return any cell's text. It moves with the frame through `head`, `tail`, `rows`,\n * `select`, `toDict` and `fromDict`.\n *\n * Frozen plain data: `[{field, values, numbers, texts}]`, where a cell holding `values[i]` stands for\n * the stored symbol (`numbers[i]`, `texts[i]`), a null number meaning a pure string and a null text a\n * pure number.\n *\n * @return {QvdStoredSymbols|null} The record, or null when the frame has none: every cell of the read\n * showed its whole symbol, or the frame was built without one. A frame whose columns have no entry\n * in the record it was given or found - one from `select`, or one built from some of a read's\n * columns and its header - has an empty record rather than null, because a frame given null takes\n * the record its header carries, which describes every field of the read.\n */\n get storedSymbols() {\n return this._storedSymbols;\n }\n\n /**\n * Returns statistics about the read that produced this data frame.\n *\n * Carried by every frame that came from a file - `fromQvd()`, and each chunk `iterate()` yields,\n * which is how a chunk reports its `offset`. `fromDict()`, `head()`, `tail()`, `rows()` and\n * `select()` describe no particular read and report null rather than a stale figure.\n *\n * The main use is confirming that a lazy load actually filtered the symbol table:\n * `symbolFiltering` says whether the two-pass path ran, and `symbolsKept` how many symbols\n * survived it. Note that a bounded read does not filter on its own - the two-pass path engages\n * only above `symbolFilteringThreshold`, so on a file below it this reports false and every\n * symbol was parsed however few rows were asked for.\n *\n * @return {QvdLoadStats|null} Load statistics, or null if this frame did not come from a file.\n */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * Returns file-level metadata from the QVD header.\n * @return {Object} File-level metadata properties.\n */\n get fileMetadata() {\n if (!this._metadata) {\n return {};\n }\n\n const header = this._metadata;\n return {\n qvBuildNo: header.QvBuildNo,\n creatorDoc: header.CreatorDoc,\n createUtcTime: header.CreateUtcTime,\n sourceCreateUtcTime: header.SourceCreateUtcTime,\n sourceFileUtcTime: header.SourceFileUtcTime,\n sourceFileSize: header.SourceFileSize,\n staleUtcTime: header.StaleUtcTime,\n tableName: header.TableName,\n noOfRecords: header.NoOfRecords,\n recordByteSize: header.RecordByteSize,\n offset: header.Offset,\n length: header.Length,\n compression: header.Compression,\n comment: header.Comment,\n encryptionInfo: header.EncryptionInfo,\n tableTags: header.TableTags,\n profilingData: header.ProfilingData,\n lineage: header.Lineage,\n };\n }\n\n /**\n * Returns field-level metadata for a specific field/column.\n * @param {string} fieldName The name of the field.\n * @return {Object|null} Field metadata or null if field not found.\n */\n getFieldMetadata(fieldName) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return null;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const field = fields.find((f) => f.FieldName === fieldName);\n if (!field) {\n return null;\n }\n\n return {\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n };\n }\n\n /**\n * Returns field-level metadata for all fields.\n * @return {Array<Object>} Array of field metadata objects.\n */\n getAllFieldMetadata() {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return [];\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n return fields.map((field) => ({\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n }));\n }\n\n /**\n * @typedef {Object} FileMetadataUpdate\n * @property {string|number} [qvBuildNo] - QlikView build number\n * @property {string} [creatorDoc] - Creator document\n * @property {string} [createUtcTime] - Creation UTC time\n * @property {string} [sourceCreateUtcTime] - Source creation UTC time\n * @property {string} [sourceFileUtcTime] - Source file UTC time\n * @property {string|number} [sourceFileSize] - Source file size\n * @property {string} [staleUtcTime] - Stale UTC time\n * @property {string} [tableName] - Table name\n * @property {string} [compression] - Compression type\n * @property {string} [comment] - Comment\n * @property {string} [encryptionInfo] - Encryption info\n * @property {string} [tableTags] - Table tags\n * @property {string} [profilingData] - Profiling data\n * @property {Object|string} [lineage] - Lineage\n */\n\n /**\n * The header a metadata setter may change: this frame's own.\n *\n * A frame's header can be shared. `head`, `tail`, `rows` and `select` pass theirs on, every chunk\n * `iterate()` yields holds the same one, and `fromDict` uses the object it is given. So the first\n * change copies it, and a change made through one frame never reaches another. A frame with no header\n * gets the one `toQvd` would write for it. The copy keeps the stored-symbol record the header carries,\n * so `new QvdDataFrame(data, columns, df.metadata)` still writes what `df` would.\n *\n * @return {any} The header.\n */\n _ownMetadata() {\n if (!this._metadata) {\n this._metadata = defaultHeader(this._columns);\n } else if (!this._ownsMetadata) {\n // @ts-ignore - a symbol-keyed property the reader defines on the header object\n const record = this._metadata[STORED_SYMBOLS];\n this._metadata = structuredClone(this._metadata);\n if (record) {\n attachStoredSymbols(this._metadata, record);\n }\n }\n this._ownsMetadata = true;\n return this._metadata;\n }\n\n /**\n * Sets modifiable file-level metadata. Immutable properties related to data storage are ignored.\n *\n * The change applies to this frame only, never to a frame it was derived from or shares a header\n * with.\n *\n * @param {FileMetadataUpdate} metadata Object containing metadata properties to update.\n */\n setFileMetadata(metadata) {\n const header = this._ownMetadata();\n\n // Only allow modification of certain fields (not Offset, Length, NoOfRecords, RecordByteSize)\n const modifiableFields = [\n 'qvBuildNo',\n 'creatorDoc',\n 'createUtcTime',\n 'sourceCreateUtcTime',\n 'sourceFileUtcTime',\n 'sourceFileSize',\n 'staleUtcTime',\n 'tableName',\n 'compression',\n 'comment',\n 'encryptionInfo',\n 'tableTags',\n 'profilingData',\n 'lineage',\n ];\n\n // Map camelCase to XML property names\n const fieldMapping = {\n qvBuildNo: 'QvBuildNo',\n creatorDoc: 'CreatorDoc',\n createUtcTime: 'CreateUtcTime',\n sourceCreateUtcTime: 'SourceCreateUtcTime',\n sourceFileUtcTime: 'SourceFileUtcTime',\n sourceFileSize: 'SourceFileSize',\n staleUtcTime: 'StaleUtcTime',\n tableName: 'TableName',\n compression: 'Compression',\n comment: 'Comment',\n encryptionInfo: 'EncryptionInfo',\n tableTags: 'TableTags',\n profilingData: 'ProfilingData',\n lineage: 'Lineage',\n };\n\n modifiableFields.forEach((field) => {\n // @ts-ignore - Dynamic property access for metadata mapping\n if (metadata[field] !== undefined) {\n // @ts-ignore - Dynamic property access for metadata mapping\n header[fieldMapping[field]] = metadata[field];\n }\n });\n }\n\n /**\n * @typedef {Object} FieldMetadataUpdate\n * @property {string} [comment] - Field comment\n * @property {QvdNumberFormat|string} [numberFormat] - Number format\n * @property {Object|string} [tags] - Field tags\n */\n\n /**\n * Sets modifiable field-level metadata for a specific field.\n * Immutable properties related to data storage (Offset, Length, BitOffset, etc.) are ignored.\n *\n * Works on any frame, including one with no header yet - one from `fromDict` - and on a column the\n * header does not describe. The change applies to this frame only, never to a frame it was derived\n * from or shares a header with.\n *\n * @param {string} fieldName The name of the field.\n * @param {FieldMetadataUpdate} metadata Object containing field metadata properties to update.\n * @throws {QvdValidationError} If the frame has no column of that name.\n */\n setFieldMetadata(fieldName, metadata) {\n if (!this._columns.includes(fieldName)) {\n throw new QvdValidationError(`Column '${fieldName}' does not exist`, {\n column: fieldName,\n availableColumns: this._columns,\n });\n }\n\n const header = this._ownMetadata();\n if (!header.Fields || typeof header.Fields !== 'object' || !header.Fields.QvdFieldHeader) {\n header.Fields = {QvdFieldHeader: []};\n }\n\n let fields = header.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n header.Fields.QvdFieldHeader = fields;\n }\n\n let field = fields.find((/** @type {any} */ f) => f.FieldName === fieldName);\n if (!field) {\n field = defaultFieldHeader(fieldName);\n fields.push(field);\n }\n\n // Only allow modification of Comment, NumberFormat, and Tags (not Offset, Length, BitOffset, etc.)\n if (metadata.comment !== undefined) {\n field.Comment = metadata.comment;\n }\n if (metadata.numberFormat !== undefined) {\n field.NumberFormat = metadata.numberFormat;\n }\n if (metadata.tags !== undefined) {\n field.Tags = metadata.tags;\n }\n }\n\n /**\n * Returns the first n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n head(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('head() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(this._data.slice(0, n), this._columns, this._metadata, null, this._storedSymbols);\n }\n\n /**\n * Returns the last n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n tail(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('tail() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(\n n === 0 ? [] : this._data.slice(-n),\n this._columns,\n this._metadata,\n null,\n this._storedSymbols,\n );\n }\n\n /**\n * Returns the selected rows of the data frame.\n *\n * @param {...number} args The indices of the rows to return.\n * @return {QvdDataFrame} The selected rows of the data frame.\n * @throws {QvdValidationError} If any index is not an integer or is out of bounds.\n */\n rows(...args) {\n for (const index of args) {\n if (typeof index !== 'number' || !Number.isInteger(index)) {\n throw new QvdValidationError('rows() requires integer indices', {\n provided: index,\n type: typeof index,\n });\n }\n if (index < 0 || index >= this._data.length) {\n throw new QvdValidationError(`Row index ${index} out of bounds`, {\n index,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n }\n return new QvdDataFrame(\n args.map((index) => this._data[index]),\n this._columns,\n this._metadata,\n null,\n this._storedSymbols,\n );\n }\n\n /**\n * Returns the value at the specified row and column.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {any} The value at the specified row and column.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n at(row, column) {\n const index = this._cellIndex(row, column);\n\n return this._data[row][index];\n }\n\n /**\n * Returns the text of the value at the specified row and column.\n *\n * The text Qlik displays for it: a string cell is its own text, and a dual cell's text is its\n * `.text`. A number cell's text comes from the frame's `storedSymbols` - the dual it was read from,\n * or the string it was spelled as - and is null for a number that was stored as a pure number.\n *\n * ```js\n * const df = await QvdDataFrame.fromQvd('stockholm_temp.qvd');\n * df.at(0, 'date'); // -52593\n * df.textAt(0, 'date'); // '1756-01-01'\n * ```\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {string|null} The text, or null for NULL and for a number with no text.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n textAt(row, column) {\n const index = this._cellIndex(row, column);\n const value = this._data[row][index];\n\n if (typeof value === 'string') {\n return value;\n }\n\n if (typeof value === 'number') {\n const entry = storedSymbolsEntry(this._storedSymbols, column);\n\n return entry === null ? null : storedTextOf(entry, value);\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.text === 'string' ? dual.text : null;\n }\n\n /**\n * Checks a row and a column name, and returns the column's position.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {number} The column's position.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n * @private\n */\n _cellIndex(row, column) {\n if (typeof row !== 'number' || !Number.isInteger(row)) {\n throw new QvdValidationError('Row index must be an integer', {\n provided: row,\n type: typeof row,\n });\n }\n if (row < 0 || row >= this._data.length) {\n throw new QvdValidationError(`Row index ${row} out of bounds`, {\n index: row,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n return this._columns.indexOf(column);\n }\n\n /**\n * Selects the specified columns from the data frame.\n *\n * @param {...string} args The names of the columns to select.\n * @return {QvdDataFrame} The selected columns of the data frame.\n * @throws {QvdValidationError} If any column name does not exist.\n */\n select(...args) {\n for (const column of args) {\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n }\n const indices = args.map((arg) => this._columns.indexOf(arg));\n const data = this._data.map((row) => indices.map((index) => row[index]));\n const columns = indices.map((index) => this._columns[index]);\n // The constructor narrows the record to the fields kept, sharing their entries rather than copying them.\n return new QvdDataFrame(data, columns, this._metadata, null, this._storedSymbols);\n }\n\n /**\n * Returns the data frame as a dictionary.\n *\n * Everything a frame needs to write the same file again, as plain data: the header, and the\n * stored-symbol record that says what cells showing one half of a symbol were read from. So\n * `fromDict(await df.toDict())` writes what `df` writes, and so does a dictionary that went through\n * `JSON`, `structuredClone` or a worker on the way. The arrays are the frame's own, not copies.\n *\n * @return {Promise<QvdDataFrameDict>} The data frame as a dictionary.\n */\n async toDict() {\n return this.toJSON();\n }\n\n /**\n * The same dictionary `toDict` returns, synchronously, so `JSON.stringify(df)` gives something\n * `fromDict(JSON.parse(...))` can revive.\n *\n * @return {QvdDataFrameDict} The data frame as a dictionary.\n */\n toJSON() {\n return {\n columns: this._columns,\n data: this._data,\n metadata: this._metadata,\n storedSymbols: this._storedSymbols,\n };\n }\n\n /**\n * Persists the data frame to a QVD file.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional writing options.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function that receives progress updates during write operations.\n * @param {boolean} [options.atomic=true] Whether to replace the file rather than rewrite it. The QVD\n * is built beside it under a temporary name and renamed over it, so a write that fails leaves the\n * previous file exactly as it was, and a reader of the path - a Qlik reload, say - sees the old\n * file or the new one and never a part of either. False rewrites the file where it stands, as\n * every version before 2.0.0 did: that keeps its identity, including hard links, its owner and\n * permissions set on the file itself, and needs neither room for two copies nor permission to\n * create files in the directory. It also destroys the previous file as the write begins. A file\n * that does not exist yet is renamed into place either way, since there is nothing to rewrite.\n * @param {boolean} [options.fsync=true] Whether to wait for the contents to reach the disk before\n * resolving. It is what carries an atomic write's promise through a power loss - the contents are\n * on the disk before anything is renamed, so a crash leaves the previous file or the new one and\n * never a damaged one - and what reports a failing disk's deferred error instead of losing it. The\n * rename itself is not flushed, so a crash just after the call can still lose the replacement, or\n * a file that did not exist before. False resolves once the operating system has accepted the\n * bytes, which is faster and is what every version before 2.0.0 did.\n */\n async toQvd(path, options = {}) {\n const {QvdFileWriter} = await import('./QvdFileWriter.js');\n const writerOptions = {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n atomic: options.atomic,\n fsync: options.fsync,\n };\n await new QvdFileWriter(path, this, writerOptions).save();\n }\n\n /**\n * Loads a QVD file and returns its data frame.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional loading options.\n * @param {number|null} [options.maxRows] The maximum number of rows to load. Must be a non-negative\n * integer; if not specified or null, all rows are loaded. Anything else throws a QvdValidationError.\n * This is the older name for `limit`; the two are the same option and passing both throws.\n * @param {number|null} [options.limit] Rows to read, counting from `offset`. The same number as\n * `maxRows`, spelled so that it reads correctly beside an offset.\n * @param {number} [options.offset=0] File row to start at. An offset past the end of the file\n * returns no rows rather than throwing, so a paging loop terminates on its own.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear in the result. Unselected fields have their symbols skipped entirely rather than\n * parsed and discarded. An unknown or repeated name throws.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol - a number with the\n * text Qlik displays for it, such as a date, a timestamp or a formatted amount - reads as.\n * `'number'` gives its number, the value Qlik sums, sorts and compares by, so a date is its serial.\n * `'text'` gives its text. `'both'` gives a frozen `QvdDual` with `.number` and `.text`, whose\n * implicit conversions throw. Under `'number'` and `'text'` the other half is kept in\n * `storedSymbols`, so `toQvd` writes the dual back, and `textAt` returns any cell's text. An int, a\n * double, a string and NULL read the same in every mode: a number, a string and null. Anything else\n * throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite. A string symbol then\n * reads as `Number(text)`, so `'007'` is 7, in every `duals` mode; a dual read with\n * `duals: 'text'` reads as the number it stores. Blank text, and text such as `'8E5597'` whose\n * `Number()` is Infinity, stay strings. The text is kept in `storedSymbols`, so `toQvd` writes the\n * original string or dual back, and a value that two stored values read as is refused there\n * rather than written as either. Anything but a boolean throws.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}` as the\n * read proceeds - the same shape `toQvd`'s callback receives.\n * @param {AbortSignal} [options.signal] Cancels the read. The rejection is `signal.reason`,\n * which is a `DOMException` named `AbortError` unless you aborted with a reason of your own.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction (0.0-1.0) of the memory budget a load\n * may use. The budget is the smaller of the V8 heap limit and any container memory limit. Default\n * is 0.8; the estimate it scales accounts for the rows and columns being materialised, so this is\n * headroom for garbage collection rather than compensation for an inaccurate figure.\n * **Zero disables the memory check entirely.**\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes, above which\n * a lazy load switches to the two-pass filtering path. Defaults to 50MB.\n * @throws {QvdValidationError} If a window option is not a non-negative integer, if both\n * `maxRows` and `limit` are given, if `fields` names a column the file does not have, if `duals`\n * is not one of its modes, or if `coerceNumericStrings` is not a boolean.\n * @return {Promise<QvdDataFrame>} The data frame of the QVD file.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n return await new QvdFileReader(path, readerOptionsFrom(options)).load(windowFrom(options));\n }\n\n /**\n * Reads a QVD file in chunks, as an async generator of data frames.\n *\n * The file is opened once and its symbol table parsed once. Each chunk's records are read from the\n * file when that chunk is built, so what this holds is the symbol table and two chunks of rows,\n * whatever the size of the file: a 20 GB QVD iterates in the memory its symbol table needs. That\n * table is still parsed in full whatever the chunk size, because a stored index in the last chunk\n * can address the first symbol. On a high-cardinality file that table is the bulk of the cost, and\n * `readMetadata` is the only read that avoids it.\n *\n * The file stays open until the iteration ends. Running it to the end closes it, and so do\n * `break` or a throw inside `for await` and a call to `return()` on the iterator; an iterator\n * abandoned part-way without any of those holds the file until it is garbage-collected.\n *\n * ```js\n * for await (const chunk of QvdDataFrame.iterate('big.qvd', {chunkSize: 50_000})) {\n * process(chunk.data);\n * }\n * ```\n *\n * A window covering no rows yields nothing, so a loop over an exhausted offset simply does not\n * run its body.\n *\n * Every chunk carries the same `storedSymbols`, because the symbol table is parsed once for all of\n * them, so a chunk written on its own writes the symbols its cells were read from.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Reading options, with the meanings they have on `fromQvd`.\n * @param {number} [options.chunkSize=100000] Rows per frame. Must be a positive integer.\n * @param {number|null} [options.maxRows] Rows to cover. The older name for `limit`.\n * @param {number|null} [options.limit] Rows to cover, counting from `offset`.\n * @param {number} [options.offset=0] File row to start at.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should appear.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol reads as: its number,\n * its text, or a frozen `QvdDual` holding both. Anything else throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite - a string symbol as\n * `Number(text)`, a dual read as text as its stored number - with the text kept in every chunk's\n * `storedSymbols`. Anything but a boolean throws.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}`; progress\n * over the rows counts the whole window, not each chunk.\n * @param {AbortSignal} [options.signal] Cancels the iteration, rejecting with `signal.reason`.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction of the memory budget the read may use,\n * charged for two chunks of rows rather than the window. Zero disables the check.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size above which a\n * windowed read switches to two-pass filtering.\n * @return {AsyncGenerator<QvdDataFrame>} The chunks, in file order.\n */\n static async *iterate(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n const reader = new QvdFileReader(path, readerOptionsFrom(options));\n\n yield* reader.iterateRows(windowFrom(options), options.chunkSize === undefined ? 100000 : options.chunkSize);\n }\n\n /**\n * Reads a QVD file's schema and header metadata, without reading its data.\n *\n * Costs the same whatever the file's size, because it stops at the XML header - a few\n * kilobytes - and never touches the symbol or index tables.\n *\n * This is what `{maxRows: 0}` looks like but is not. That still reads and parses the whole\n * symbol table, which is 0.4MB on a 38MB taxi fixture but hundreds of megabytes on a\n * high-cardinality file. Use this when you want to know what is in a file rather than to\n * read any of it.\n *\n * No data frame comes back, deliberately: one with `data: []` would be indistinguishable\n * from an empty file at the call site.\n *\n * ```js\n * const {columns, rowCount, fields} = await QvdDataFrame.readMetadata('sales.qvd');\n * ```\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional reading options.\n * @param {string} [options.allowedDir] Optional allowed directory path, applied exactly as it\n * is for `fromQvd`.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}`, as on\n * the reads that return data. Only the `read` and `header` stages occur here; there are no\n * symbols to parse and no rows to build.\n * @param {AbortSignal} [options.signal] Cancels the read, rejecting with `signal.reason`.\n * @return {Promise<QvdFileMetadata>} The file's schema and header metadata.\n */\n static async readMetadata(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n return await new QvdFileReader(path, metadataOptionsFrom(options)).loadMetadata();\n }\n\n /**\n * Answers what a read would cost, and whether it fits, without doing it.\n *\n * Takes the options `fromQvd()` takes, plus `as` and `chunkSize` to say which read is being asked\n * about. Reads the header and the file's size and nothing else, at a cost that does not grow with\n * the file.\n *\n * The answer comes from the same function a read consults before it allocates anything, from the\n * same numbers, so **a read this approves is not refused later for memory** - and every suggestion\n * it carries has been read back through the check, so following one gives a read that fits.\n *\n * It answers about resources, so it answers only for a header it can trust. A header whose numbers\n * are not usable, or that claims more than the file holds, is refused as a `QvdCorruptedError` rather\n * than answered: sizing a read from numbers the file contradicts produced a memory verdict about a\n * file whose real problem was structural, and it was wrong in both directions - approving a read the\n * library then refused, and refusing another with advice that was refused too.\n *\n * That covers everything a reader can tell from the header: a field area past the end of the symbol\n * table, two fields claiming one area, a `Bias` that is neither 0 nor -2, a `BitWidth` past 31. Damage\n * that is not in the header - a value or an index the file has spoiled - is still found only by\n * reading, and still refused as a `QvdCorruptedError` after this has said the read fits.\n *\n * ```js\n * const answer = await QvdDataFrame.checkRead('huge.qvd', {as: 'columns', fields: ['Amount']});\n *\n * if (!answer.fits) {\n * console.log(answer.reason); // 'memory'\n * console.log(answer.suggestions); // [{option: 'limit', value: 1250000}, ...]\n * }\n * ```\n *\n * @param {string} path The QVD file.\n * @param {object} [options] What `fromQvd()` takes, plus the two below.\n * @param {'rows'|'columns'} [options.as='rows'] Which read is being asked about: `rows` builds row\n * arrays and `columns` does not, which is most of what a read costs.\n * @param {number|null} [options.chunkSize=null] The chunk an `iterate()` would use, which holds two\n * chunks of rows rather than the whole window.\n * @return {Promise<any>} The answer: `fits`, `reason` when it does not, `estimate`, `budget`,\n * `exact` and `suggestions`.\n * @throws {QvdValidationError} If an option's value is not valid, with `context.reason` of `option`.\n * @throws {QvdCorruptedError} If the header cannot be read, its numbers are not usable, or it claims\n * more than the file holds. The read refuses such a file too, though it may name the fault\n * differently - it gets there by planning the index table, where this gets there from the size.\n */\n static async checkRead(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const {as = 'rows', chunkSize = null} = options;\n\n if (as !== 'rows' && as !== 'columns') {\n throw new QvdValidationError(\"as must be 'rows' or 'columns'\", {\n provided: as,\n reason: 'option',\n option: 'as',\n value: as,\n file: path,\n });\n }\n\n if (chunkSize !== null) {\n requireChunkSize(chunkSize, path);\n }\n\n const reader = new QvdFileReader(path, {...readerOptionsFrom(options), materialisesRows: as === 'rows'});\n\n return await reader.checkRead(windowFrom(options), {chunkSize});\n }\n\n /**\n * Opens a QVD file for paging, reading its header and nothing else.\n *\n * Every other entry point is one read from start to finish. A viewer showing a hundred rows at a time\n * pays the header again on every page, and `iterate()` goes forwards only - it cannot jump to row five\n * million and it cannot go back. This holds the header so that `check()` costs nothing and a page can\n * be asked for by position.\n *\n * ```js\n * const qvd = await QvdDataFrame.open('sales.qvd', {allowedDir: '/data'});\n *\n * qvd.metadata; // read once, when it opened\n * const answer = qvd.check({offset: 0, limit: 100}); // no I/O at all\n * const page = await qvd.rows({offset: 5_000_000, limit: 100});\n * const cols = await qvd.columns({offset: 0, limit: 100, fields: ['Amount']});\n *\n * await qvd.close();\n * ```\n *\n * The header is read once, and so is each column: a column decoded for one page is kept for the pages\n * after it, so the first page costs about what a single read costs and the ones after it are cheap.\n * What a file has decoded is charged to the memory check, so a page is refused rather than the process\n * aborting, and `close()` releases it - close a file you have finished with.\n *\n * Each page still opens the file, and a first touch still decodes a whole column rather than only as\n * far as the page needs.\n *\n * @param {string} path The QVD file.\n * @param {object} [options] What `fromQvd()` takes - `allowedDir`, `fields`, `duals`,\n * `coerceNumericStrings`, `memorySafetyFactor` - describing the file and how its values read. A\n * window means nothing here: pages carry their own.\n * @return {Promise<import('./QvdFile.js').QvdFile>} The open file.\n * @throws {QvdValidationError} If an option's value is not valid, with `context.reason` of `option`.\n * @throws {QvdCorruptedError} If the header cannot be read, or describes a file this is not.\n */\n static async open(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const {QvdFile} = await import('./QvdFile.js');\n\n // One reader, holding the parsed header for the life of the file: it answers `check()` and nothing\n // else, so the state a page would clear is never its state. Pages get readers of their own.\n const reader = new QvdFileReader(path, readerOptionsFrom(options));\n\n // Paging, though it will never read a row: every page of this file is made by a paging reader, so\n // the estimates this one answers `check()` with have to be paging estimates. Without it a check\n // made before the first page priced a window's sample of the symbols, and the page that followed\n // held every one of them - the check and the read disagreeing about the same page.\n reader.beginPaging();\n\n // One header read, not two: the checks a page will rely on, then the schema built from the same\n // parse. Reading it once for the metadata and again for the checks would have opened the file twice\n // to answer one question.\n await reader.parseHeaderOnly();\n\n return new QvdFile(reader, reader.describeParsed(), {...options, path});\n }\n\n /**\n * Constructs a data frame from a dictionary.\n *\n * Takes what `toDict` returns. `metadata` and `storedSymbols` are optional; with the record, a frame\n * rebuilt from a read writes the symbols the read found - duals with their texts, strings with their\n * spelling - even after a trip through `JSON`. The record is checked, so a malformed one is refused\n * here rather than written.\n *\n * @param {QvdDataFrameDict} data The dictionary to construct the data frame from.\n * @return {Promise<QvdDataFrame>} The constructed data frame.\n * @throws {QvdValidationError} If `columns` or `data` is missing, `metadata` is not a plain object,\n * or `storedSymbols` is malformed or names a field that is not one of the columns.\n */\n static async fromDict(data) {\n if (!data.columns) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any columns.', {\n data,\n });\n }\n if (!data.data) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any data.', {\n data,\n });\n }\n\n const {metadata = null, storedSymbols = null} = data;\n\n if (metadata !== null && !isPlainObject(metadata)) {\n throw new QvdValidationError(`metadata must be a plain object; got ${describeType(metadata)}`, {\n type: typeof metadata,\n });\n }\n\n const record = normaliseStoredSymbols(storedSymbols);\n\n if (record !== null) {\n const unknown = record.find((entry) => !data.columns.includes(entry.field));\n\n if (unknown !== undefined) {\n throw new QvdValidationError(`storedSymbols names field '${unknown.field}', which is not one of the columns`, {\n field: unknown.field,\n availableColumns: data.columns,\n });\n }\n }\n\n return new QvdDataFrame(data.data, data.columns, metadata, null, record);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {INT32_MAX, INT32_MIN, asDual, checkNumber, checkText, describeType, isStoredAsInt} from './util/cellRules.js';\nimport {symbolByteLength, writeSymbol} from './util/symbolBytes.js';\n\n/**\n * Throws unless a value can be stored as the integer of a symbol.\n *\n * @param {any} value The value.\n * @param {Object} context Merged into the error's context.\n * @throws {QvdValidationError} If the value is not an integer inside the int32 range.\n */\nfunction checkInteger(value, context) {\n if (typeof value === 'number' && isStoredAsInt(value)) {\n return;\n }\n\n throw new QvdValidationError(\n `The integer of a symbol must be an integer from ${INT32_MIN} to ${INT32_MAX}; got ` +\n (typeof value === 'number' ? String(value) : describeType(value)),\n {...context, half: 'integer', type: typeof value},\n );\n}\n\n/**\n * One stored symbol, as the symbol table holds it: an int, a double, a string, or a dual of an int or\n * a double with its text.\n *\n * A low-level record of the file's contents rather than a cell. A read never puts one in a data frame\n * - a cell is a number, a string, a `QvdDual` or null - and the writer refuses one as a cell, pointing\n * at `QvdDual`, because a symbol carries a storage kind the writer derives from the value itself.\n *\n * The factories validate what they are given and throw `QvdValidationError` naming the half, so a\n * symbol built through them can be encoded. The constructor checks nothing, and\n * `toByteRepresentation` refuses whatever it cannot encode.\n */\nexport class QvdSymbol {\n /**\n * Constructs a new QVD symbol.\n *\n * @param {number|null} intValue The integer value.\n * @param {number|null} doubleValue The double value.\n * @param {string|null} stringValue The string value.\n */\n constructor(intValue, doubleValue, stringValue) {\n this._intValue = intValue;\n\n this._doubleValue = doubleValue;\n\n this._stringValue = stringValue;\n }\n\n /**\n * Returns the integer value of this symbol.\n *\n * @return {number|null} The integer value.\n */\n get intValue() {\n return this._intValue;\n }\n\n /**\n * Returns the double value of this symbol.\n *\n * @return {number|null} The double value.\n */\n get doubleValue() {\n return this._doubleValue;\n }\n\n /**\n * Returns the string value of this symbol.\n *\n * @return {string|null} The string value.\n */\n get stringValue() {\n return this._stringValue;\n }\n\n /**\n * Retrieves the primary value of this symbol. The primary value is descriptive raw value.\n * It is either the string value, the integer value or the double value, prioritized in this order.\n *\n * @return {number|string|null} The primary value.\n */\n toPrimaryValue() {\n if (null != this._stringValue) {\n return this._stringValue;\n } else if (null != this._intValue) {\n return this._intValue;\n } else if (null != this._doubleValue) {\n return this._doubleValue;\n } else {\n return null;\n }\n }\n\n /**\n * Converts the symbol to its byte representation.\n *\n * The kind is the one the symbol carries - an int, a double, a string, or a dual of an int or a\n * double with its text - so a symbol built with `fromDoubleValue(4)` stays a double. Each half is\n * checked before a byte is written, because `QvdSymbol`'s constructor checks nothing: an integer\n * outside int32 used to surface as a bare `RangeError` from `writeInt32LE`, a symbol holding an\n * integer and a double silently lost the double, a text with a NUL produced a symbol that ends\n * early, and a text with an unpaired surrogate was written with U+FFFD in its place.\n *\n * A half left `undefined` - `new QvdSymbol()`, or `new QvdSymbol(7)` - is absent, as it is to\n * `toPrimaryValue`. It used to be read as present: `new QvdSymbol(7)` threw a bare `TypeError` from\n * `Buffer.from`, and `new QvdSymbol(undefined, 4.5, '4.50')` was written as a dual of the integer 0.\n *\n * @return {Buffer} The byte representation of the symbol.\n * @throws {QvdValidationError} If the symbol holds both an integer and a double, holds nothing, or\n * holds a half no symbol can store. The message names the half.\n */\n toByteRepresentation() {\n const intValue = this._intValue ?? null;\n const doubleValue = this._doubleValue ?? null;\n const stringValue = this._stringValue ?? null;\n\n if (intValue !== null && doubleValue !== null) {\n throw new QvdValidationError('A symbol holds an integer or a double, not both', {\n intValue,\n doubleValue,\n });\n }\n\n if (intValue === null && doubleValue === null && stringValue === null) {\n throw new QvdValidationError('The symbol does not contain any value.', {\n intValue,\n doubleValue,\n stringValue,\n });\n }\n\n if (intValue !== null) {\n checkInteger(intValue, {});\n }\n\n if (doubleValue !== null) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n }\n\n if (stringValue !== null) {\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n }\n\n const number = intValue ?? doubleValue;\n const kind = number === null ? 4 : (intValue !== null ? 1 : 2) + (stringValue !== null ? 4 : 0);\n const buffer = Buffer.allocUnsafe(symbolByteLength(kind, number, stringValue));\n\n writeSymbol(buffer, 0, kind, number, stringValue);\n\n return buffer;\n }\n\n /**\n * Checks if this symbol is equal to another symbol.\n *\n * By shape rather than by class: another value is equal when its `intValue`, `doubleValue` and\n * `stringValue` are, compared with `===`, whichever copy of this library built it - `instanceof`\n * answers false for a symbol from the CommonJS build tested by the ESM one. A dual value, a `QvdDual`\n * or `{number, text}`, is equal to a dual symbol with the same number and text: a dual carries no\n * storage kind, so either kind matches.\n *\n * @param {*} value The object to compare with.\n * @return {boolean} True if the objects are equal, false otherwise.\n */\n equals(value) {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n const intValue = this._intValue ?? null;\n const doubleValue = this._doubleValue ?? null;\n const stringValue = this._stringValue ?? null;\n const dual = asDual(value);\n\n if (dual !== null) {\n return (\n stringValue !== null &&\n stringValue === dual.text &&\n (intValue === null) !== (doubleValue === null) &&\n (intValue ?? doubleValue) === dual.number\n );\n }\n\n if (!('intValue' in value && 'doubleValue' in value && 'stringValue' in value)) {\n return false;\n }\n\n return (\n intValue === (value.intValue ?? null) &&\n doubleValue === (value.doubleValue ?? null) &&\n stringValue === (value.stringValue ?? null)\n );\n }\n\n /**\n * Constructs a pure integer value symbol.\n *\n * @param {number} intValue The integer value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the integer is not an integer inside the int32 range.\n */\n static fromIntValue(intValue) {\n checkInteger(intValue, {});\n\n return new QvdSymbol(intValue, null, null);\n }\n\n /**\n * Constructs a pure double value symbol.\n *\n * @param {number} doubleValue The double value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the double is not a finite number.\n */\n static fromDoubleValue(doubleValue) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n\n return new QvdSymbol(null, doubleValue, null);\n }\n\n /**\n * Constructs a pure string value symbol.\n *\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the string is not a string, or holds a NUL or an unpaired surrogate.\n */\n static fromStringValue(stringValue) {\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\n return new QvdSymbol(null, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from an integer and a string value.\n *\n * @param {number} intValue The integer value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the integer is not an integer inside the int32 range, or the text\n * is not a string, or holds a NUL or an unpaired surrogate.\n */\n static fromDualIntValue(intValue, stringValue) {\n checkInteger(intValue, {});\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\n return new QvdSymbol(intValue, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from a double and a string value.\n *\n * @param {number} doubleValue The double value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n * @throws {QvdValidationError} If the double is not a finite number, or the text is not a string,\n * or holds a NUL or an unpaired surrogate.\n */\n static fromDualDoubleValue(doubleValue, stringValue) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\n return new QvdSymbol(null, doubleValue, stringValue);\n }\n}\n","// @ts-check\n\nexport {QvdSymbol} from './QvdSymbol.js';\nexport {QvdDual} from './QvdDual.js';\nexport {qlikSerialToDate, dateToQlikSerial} from './util/qlikDate.js';\nexport {QvdDataFrame} from './QvdDataFrame.js';\nexport {QvdColumnTable, QvdColumn} from './QvdColumnTable.js';\nexport {QvdFile} from './QvdFile.js';\nexport {QvdFileReader} from './QvdFileReader.js';\nexport {QvdFileWriter} from './QvdFileWriter.js';\nexport {\n QvdError,\n QvdParseError,\n QvdValidationError,\n QvdIOError,\n QvdCorruptedError,\n QvdSecurityError,\n} from './QvdErrors.js';\n","// @ts-check\n\nimport {types} from 'util';\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {asDual, describeType} from './cellRules.js';\n\n/** Qlik's day 0: 30 December 1899, so that 1 January 1900 is day 2, as in Excel and Lotus 1-2-3. */\nconst QLIK_EPOCH_MS = Date.UTC(1899, 11, 30);\n\nconst MS_PER_DAY = 86400000;\n\n/** The furthest a JavaScript `Date` reaches either side of 1970, in milliseconds. */\nconst MAX_DATE_MS = 8.64e15;\n\n/** The serials of the first and last days a `Date` can hold: -99974431 and 100025569. */\nconst MIN_SERIAL = (-MAX_DATE_MS - QLIK_EPOCH_MS) / MS_PER_DAY;\nconst MAX_SERIAL = (MAX_DATE_MS - QLIK_EPOCH_MS) / MS_PER_DAY;\n\n/**\n * Converts a Qlik date or timestamp serial to a JavaScript `Date`.\n *\n * Qlik stores a date as the number of days since 30 December 1899, with the time of day as the\n * fraction: 42382.260416666664 is 13 January 2016 at 06:15. That number is what a date field's cell\n * reads as, whether Qlik stored it as a dual with the date's text or as a pure number with a `DATE`\n * format - and it is the `number` of a dual value read with `{duals: 'both'}`.\n *\n * **The serial has no time zone, and the result is read in UTC.** Qlik's serial means \"this wall-clock\n * date and time\", not an instant. The `Date` returned carries those wall-clock fields in its UTC\n * getters, so `toISOString()` and `getUTCHours()` show what Qlik shows. The local-time getters apply\n * the machine's own offset, which is almost never what you want here.\n *\n * Checked against the text Qlik stored beside every date in stockholm_temp and every trip start\n * timestamp in a chicago_taxi_rides file, and rounded to the millisecond, which is finer than any Qlik\n * timestamp text shows.\n *\n * ```js\n * qlikSerialToDate(-52593).toISOString(); // '1756-01-01T00:00:00.000Z'\n * qlikSerialToDate(new QvdDual(-52593, '1756-01-01')).toISOString(); // a dual works too, through its number\n * ```\n *\n * @param {number|import('../QvdDual.js').QvdDual|{number: number, text: string}} serial The serial, or a dual whose number is one.\n * @return {Date} The date, with Qlik's wall-clock fields in its UTC getters.\n * @throws {QvdValidationError} If the serial is not a finite number, or is a day a `Date` cannot hold.\n */\nexport function qlikSerialToDate(serial) {\n const dual = asDual(serial);\n const number = dual === null ? serial : dual.number;\n\n if (typeof number !== 'number' || !Number.isFinite(number)) {\n throw new QvdValidationError('A Qlik date serial must be a finite number', {\n provided: describeType(number),\n type: typeof serial,\n });\n }\n\n const ms = Math.round(QLIK_EPOCH_MS + number * MS_PER_DAY);\n\n // Past this a Date is Invalid Date, which fails later and somewhere else - in toISOString(), say.\n if (!(Math.abs(ms) <= MAX_DATE_MS)) {\n throw new QvdValidationError(`A Qlik date serial of ${number} is outside the range a JavaScript Date can hold`, {\n serial: number,\n minSerial: MIN_SERIAL,\n maxSerial: MAX_SERIAL,\n });\n }\n\n return new Date(ms);\n}\n\n/**\n * Converts a JavaScript `Date` to a Qlik date or timestamp serial.\n *\n * The inverse of `qlikSerialToDate`, and it reads the date's UTC fields for the same reason: a\n * serial is a wall-clock value. Build the `Date` from UTC parts - `new Date(Date.UTC(2016, 0, 13, 6,\n * 15))`, or an ISO string ending in `Z` - to get the serial Qlik would store for that date and time.\n *\n * For every date and timestamp checked against `qlikSerialToDate`, converting Qlik's serial to a\n * `Date` and back returns Qlik's stored double exactly.\n *\n * A `Date` from another realm - a `vm` context, or a Node core module under Jest - is accepted: the\n * check is on what the value is, not on which `Date` constructor made it.\n *\n * To write a date Qlik will treat as a date, pair the serial with the text to display:\n *\n * ```js\n * const when = new Date(Date.UTC(2016, 0, 13, 6, 15));\n * const cell = new QvdDual(dateToQlikSerial(when), '2016-01-13 06:15:00');\n * ```\n *\n * @param {Date} date The date.\n * @return {number} The serial: whole days since 30 December 1899, with the time of day as the fraction.\n * @throws {QvdValidationError} If the argument is not a valid `Date`.\n */\nexport function dateToQlikSerial(date) {\n const ms = types.isDate(date) ? Date.prototype.getTime.call(date) : Number.NaN;\n\n if (Number.isNaN(ms)) {\n throw new QvdValidationError('dateToQlikSerial needs a valid Date', {\n provided: describeType(date),\n type: typeof date,\n });\n }\n\n return (ms - QLIK_EPOCH_MS) / MS_PER_DAY;\n}\n"]}