/*
 * dls-analysis v1.1.2
 * Analysis of Dynamic Light Scattering (DLS) measurements
 * https://github.com/cheminfo/dls-analysis#readme
 *
 * Licensed under the MIT license.
 */
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ZmesParser = {}));
})(this, (function (exports) { 'use strict';

    var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
    // eslint-disable-next-line @typescript-eslint/unbound-method
    const toString = Object.prototype.toString;
    /**
     * Checks if an object is an instance of an Array (array or typed array, except those that contain bigint values).
     *
     * @param value - Object to check.
     * @returns True if the object is an array or a typed array.
     */
    function isAnyArray$1(value) {
      const tag = toString.call(value);
      return tag.endsWith('Array]') && !tag.includes('Big');
    }

    var libEsm = /*#__PURE__*/Object.freeze({
        __proto__: null,
        isAnyArray: isAnyArray$1
    });

    /**
     * This function
     * @param output - undefined or a new array
     * @param length - length of the output array
     * @returns
     */
    function getOutputArray(output, length) {
      if (output !== undefined) {
        if (!isAnyArray$1(output)) {
          throw new TypeError('output option must be an array if specified');
        }
        if (output.length !== length) {
          throw new TypeError('the output array does not have the correct length');
        }
        return output;
      } else {
        return new Float64Array(length);
      }
    }

    /**
     * Calculates the median of an array.
     * @param input - Array containing values
     * @param options
     * @returns - median
     */
    function xMedian(input, options = {}) {
      if (!isAnyArray$1(input)) {
        throw new TypeError('input must be an array');
      }
      if (input.length === 0) {
        throw new TypeError('input must not be empty');
      }
      const {
        exact = false
      } = options || {};
      const array = input.slice();
      const middleIndex = calcMiddle(0, array.length - 1);
      const median = quickSelect(array, middleIndex);
      if (array.length % 2 === 1 || !exact) {
        return median;
      }
      const medianNext = quickSelect(array, middleIndex + 1);
      return (median + medianNext) / 2;
    }
    function quickSelect(array, middleIndex) {
      let low = 0;
      let high = array.length - 1;
      let middle = 0;
      let currentLow = 0;
      let currentHigh = 0;
      while (true) {
        if (high <= low) {
          return array[middleIndex];
        }
        if (high === low + 1) {
          if (array[low] > array[high]) {
            swap(array, low, high);
          }
          return array[middleIndex];
        }
        // Find median of low, middle and high items; swap into position low
        middle = calcMiddle(low, high);
        if (array[middle] > array[high]) swap(array, middle, high);
        if (array[low] > array[high]) swap(array, low, high);
        if (array[middle] > array[low]) swap(array, middle, low);
        // Swap low item (now in position middle) into position (low+1)
        swap(array, middle, low + 1);
        // Nibble from each end towards middle, swapping items when stuck
        currentLow = low + 1;
        currentHigh = high;
        while (true) {
          do currentLow++; while (array[low] > array[currentLow]);
          do currentHigh--; while (array[currentHigh] > array[low]);
          if (currentHigh < currentLow) {
            break;
          }
          swap(array, currentLow, currentHigh);
        }
        // Swap middle item (in position low) back into correct position
        swap(array, low, currentHigh);
        // Re-set active partition
        if (currentHigh <= middleIndex) {
          low = currentLow;
        }
        if (currentHigh >= middleIndex) {
          high = currentHigh - 1;
        }
      }
    }
    function swap(array, i, j) {
      const temp = array[j];
      array[j] = array[i];
      array[i] = temp;
    }
    function calcMiddle(i, j) {
      return Math.floor((i + j) / 2);
    }

    /**
     * Checks if the input is a non-empty array of numbers.
     * Only checks the first element.
     * @param input - Array to check.
     * @param options - Additional checks.
     */
    function xCheck(input, options = {}) {
      const {
        minLength
      } = options;
      if (!isAnyArray$1(input)) {
        throw new TypeError('input must be an array');
      }
      if (input.length === 0) {
        throw new TypeError('input must not be empty');
      }
      if (typeof input[0] !== 'number') {
        throw new TypeError('input must contain numbers');
      }
      if (minLength && input.length < minLength) {
        throw new Error(`input must have a length of at least ${minLength}`);
      }
    }

    /**
     * Returns the closest index of a `target`
     * @param array - array of numbers
     * @param target - target
     * @param options
     * @returns - closest index
     */
    function xFindClosestIndex(array, target, options = {}) {
      const {
        sorted = true
      } = options;
      if (sorted) {
        let low = 0;
        let high = array.length - 1;
        let middle = 0;
        while (high - low > 1) {
          middle = low + (high - low >> 1);
          if (array[middle] < target) {
            low = middle;
          } else if (array[middle] > target) {
            high = middle;
          } else {
            return middle;
          }
        }
        if (low < array.length - 1) {
          if (Math.abs(target - array[low]) < Math.abs(array[low + 1] - target)) {
            return low;
          } else {
            return low + 1;
          }
        } else {
          return low;
        }
      } else {
        let index = 0;
        let diff = Number.POSITIVE_INFINITY;
        for (let i = 0; i < array.length; i++) {
          const currentDiff = Math.abs(array[i] - target);
          if (currentDiff < diff) {
            diff = currentDiff;
            index = i;
          }
        }
        return index;
      }
    }

    /**
     * Returns an object with {fromIndex, toIndex} for a specific from / to
     * @param x - array of numbers
     * @param options - Options
     */
    function xGetFromToIndex(x, options = {}) {
      let {
        fromIndex,
        toIndex
      } = options;
      const {
        from,
        to
      } = options;
      if (fromIndex === undefined) {
        if (from !== undefined) {
          fromIndex = xFindClosestIndex(x, from);
        } else {
          fromIndex = 0;
        }
      }
      if (toIndex === undefined) {
        if (to !== undefined) {
          toIndex = xFindClosestIndex(x, to);
        } else {
          toIndex = x.length - 1;
        }
      }
      if (fromIndex < 0) fromIndex = 0;
      if (toIndex < 0) toIndex = 0;
      if (fromIndex >= x.length) fromIndex = x.length - 1;
      if (toIndex >= x.length) toIndex = x.length - 1;
      if (fromIndex > toIndex) [fromIndex, toIndex] = [toIndex, fromIndex];
      return {
        fromIndex,
        toIndex
      };
    }

    function xAbsoluteSum(array, options = {}) {
      xCheck(array);
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex(array, options);
      let sum = 0;
      for (let i = fromIndex; i <= toIndex; i++) {
        sum += Math.abs(array[i]);
      }
      return sum;
    }

    /**
     * This function xAdd the first array by the second array or a constant value to each element of the first array
     * @param array1 - the first array
     * @param array2 - the second array or number
     * @returns the result of the addition
     */
    function xAdd(array1, array2) {
      let isConstant = false;
      let constant = 0;
      if (isAnyArray$1(array2)) {
        if (array1.length !== array2.length) {
          throw new Error('size of array1 and array2 must be identical');
        }
      } else {
        isConstant = true;
        constant = array2;
      }
      const array3 = new Float64Array(array1.length);
      if (isConstant) {
        for (let i = 0; i < array1.length; i++) {
          array3[i] = array1[i] + constant;
        }
      } else {
        for (let i = 0; i < array1.length; i++) {
          array3[i] = array1[i] + array2[i];
        }
      }
      return array3;
    }

    /**
     * Will apply a function on each element of the array described as a string
     * By default we will use as variable 'x'
     * In front of sequence of lowercase we will add 'Math.'. This allows to write
     * `sin(x) + cos(x)` and it will be replace internally by (x) => (Math.sin(x) + Math.cos(x))
     * @param array
     * @param options
     * @returns
     */
    function xApplyFunctionStr(array, options = {}) {
      const {
        variableLabel = 'x',
        fctString = variableLabel
      } = options;
      const fct = new Function(variableLabel, `return Number(${fctString.replaceAll(/(?<before>^|\W)(?<after>[\da-z]{2,}\()/g, '$<before>Math.$<after>').replaceAll('Math.Math', 'Math')})`);
      const toReturn = Float64Array.from(array);
      for (let i = 0; i < array.length; i++) {
        toReturn[i] = fct(array[i]);
        if (Number.isNaN(toReturn[i])) {
          throw new Error(`The callback ${fctString} does not return a number: ${array[i]}`);
        }
      }
      return toReturn;
    }

    /**
     * This function xMultiply the first array by the second array or a constant value to each element of the first array
     * @param array1 - first array
     * @param array2 - second array
     * @param options - options
     */
    function xMultiply(array1, array2, options = {}) {
      let isConstant = false;
      let constant = 0;
      if (isAnyArray$1(array2)) {
        if (array1.length !== array2.length) {
          throw new Error('size of array1 and array2 must be identical');
        }
      } else {
        isConstant = true;
        constant = array2;
      }
      const array3 = getOutputArray(options.output, array1.length);
      if (isConstant) {
        for (let i = 0; i < array1.length; i++) {
          array3[i] = array1[i] * constant;
        }
      } else {
        for (let i = 0; i < array1.length; i++) {
          array3[i] = array1[i] * array2[i];
        }
      }
      return array3;
    }

    function getDefaultExportFromCjs (x) {
    	return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
    }

    function getAugmentedNamespace(n) {
      if (Object.prototype.hasOwnProperty.call(n, '__esModule')) return n;
      var f = n.default;
    	if (typeof f == "function") {
    		var a = function a () {
    			var isInstance = false;
          try {
            isInstance = this instanceof a;
          } catch {}
    			if (isInstance) {
            return Reflect.construct(f, arguments, this.constructor);
    			}
    			return f.apply(this, arguments);
    		};
    		a.prototype = f.prototype;
      } else a = {};
      Object.defineProperty(a, '__esModule', {value: true});
    	Object.keys(n).forEach(function (k) {
    		var d = Object.getOwnPropertyDescriptor(n, k);
    		Object.defineProperty(a, k, d.get ? d : {
    			enumerable: true,
    			get: function () {
    				return n[k];
    			}
    		});
    	});
    	return a;
    }

    var matrix = {};

    var require$$0 = /*@__PURE__*/getAugmentedNamespace(libEsm);

    function max(input) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      if (!isAnyArray$1(input)) {
        throw new TypeError('input must be an array');
      }
      if (input.length === 0) {
        throw new TypeError('input must not be empty');
      }
      var _options$fromIndex = options.fromIndex,
        fromIndex = _options$fromIndex === void 0 ? 0 : _options$fromIndex,
        _options$toIndex = options.toIndex,
        toIndex = _options$toIndex === void 0 ? input.length : _options$toIndex;
      if (fromIndex < 0 || fromIndex >= input.length || !Number.isInteger(fromIndex)) {
        throw new Error('fromIndex must be a positive integer smaller than length');
      }
      if (toIndex <= fromIndex || toIndex > input.length || !Number.isInteger(toIndex)) {
        throw new Error('toIndex must be an integer greater than fromIndex and at most equal to length');
      }
      var maxValue = input[fromIndex];
      for (var i = fromIndex + 1; i < toIndex; i++) {
        if (input[i] > maxValue) maxValue = input[i];
      }
      return maxValue;
    }

    function min(input) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      if (!isAnyArray$1(input)) {
        throw new TypeError('input must be an array');
      }
      if (input.length === 0) {
        throw new TypeError('input must not be empty');
      }
      var _options$fromIndex = options.fromIndex,
        fromIndex = _options$fromIndex === void 0 ? 0 : _options$fromIndex,
        _options$toIndex = options.toIndex,
        toIndex = _options$toIndex === void 0 ? input.length : _options$toIndex;
      if (fromIndex < 0 || fromIndex >= input.length || !Number.isInteger(fromIndex)) {
        throw new Error('fromIndex must be a positive integer smaller than length');
      }
      if (toIndex <= fromIndex || toIndex > input.length || !Number.isInteger(toIndex)) {
        throw new Error('toIndex must be an integer greater than fromIndex and at most equal to length');
      }
      var minValue = input[fromIndex];
      for (var i = fromIndex + 1; i < toIndex; i++) {
        if (input[i] < minValue) minValue = input[i];
      }
      return minValue;
    }

    function rescale$2(input) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      if (!isAnyArray$1(input)) {
        throw new TypeError('input must be an array');
      } else if (input.length === 0) {
        throw new TypeError('input must not be empty');
      }
      var output;
      if (options.output !== undefined) {
        if (!isAnyArray$1(options.output)) {
          throw new TypeError('output option must be an array if specified');
        }
        output = options.output;
      } else {
        output = new Array(input.length);
      }
      var currentMin = min(input);
      var currentMax = max(input);
      if (currentMin === currentMax) {
        throw new RangeError('minimum and maximum input values are equal. Cannot rescale a constant array');
      }
      var _options$min = options.min,
        minValue = _options$min === void 0 ? options.autoMinMax ? currentMin : 0 : _options$min,
        _options$max = options.max,
        maxValue = _options$max === void 0 ? options.autoMinMax ? currentMax : 1 : _options$max;
      if (minValue >= maxValue) {
        throw new RangeError('min option must be smaller than max option');
      }
      var factor = (maxValue - minValue) / (currentMax - currentMin);
      for (var i = 0; i < input.length; i++) {
        output[i] = (input[i] - currentMin) * factor + minValue;
      }
      return output;
    }

    var libEs6 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        default: rescale$2
    });

    var require$$1 = /*@__PURE__*/getAugmentedNamespace(libEs6);

    Object.defineProperty(matrix, '__esModule', {
      value: true
    });
    var isAnyArray = require$$0;
    var rescale$1 = require$$1;
    const indent = ' '.repeat(2);
    const indentData = ' '.repeat(4);

    /**
     * @this {Matrix}
     * @returns {string}
     */
    function inspectMatrix() {
      return inspectMatrixWithOptions(this);
    }
    function inspectMatrixWithOptions(matrix, options = {}) {
      const {
        maxRows = 15,
        maxColumns = 10,
        maxNumSize = 8,
        padMinus = 'auto'
      } = options;
      return `${matrix.constructor.name} {
${indent}[
${indentData}${inspectData(matrix, maxRows, maxColumns, maxNumSize, padMinus)}
${indent}]
${indent}rows: ${matrix.rows}
${indent}columns: ${matrix.columns}
}`;
    }
    function inspectData(matrix, maxRows, maxColumns, maxNumSize, padMinus) {
      const {
        rows,
        columns
      } = matrix;
      const maxI = Math.min(rows, maxRows);
      const maxJ = Math.min(columns, maxColumns);
      const result = [];
      if (padMinus === 'auto') {
        padMinus = false;
        loop: for (let i = 0; i < maxI; i++) {
          for (let j = 0; j < maxJ; j++) {
            if (matrix.get(i, j) < 0) {
              padMinus = true;
              break loop;
            }
          }
        }
      }
      for (let i = 0; i < maxI; i++) {
        let line = [];
        for (let j = 0; j < maxJ; j++) {
          line.push(formatNumber(matrix.get(i, j), maxNumSize, padMinus));
        }
        result.push(`${line.join(' ')}`);
      }
      if (maxJ !== columns) {
        result[result.length - 1] += ` ... ${columns - maxColumns} more columns`;
      }
      if (maxI !== rows) {
        result.push(`... ${rows - maxRows} more rows`);
      }
      return result.join(`\n${indentData}`);
    }
    function formatNumber(num, maxNumSize, padMinus) {
      return (num >= 0 && padMinus ? ` ${formatNumber2(num, maxNumSize - 1)}` : formatNumber2(num, maxNumSize)).padEnd(maxNumSize);
    }
    function formatNumber2(num, len) {
      // small.length numbers should be as is
      let str = num.toString();
      if (str.length <= len) return str;

      // (7)'0.00123' is better then (7)'1.23e-2'
      // (8)'0.000123' is worse then (7)'1.23e-3',
      let fix = num.toFixed(len);
      if (fix.length > len) {
        fix = num.toFixed(Math.max(0, len - (fix.length - len)));
      }
      if (fix.length <= len && !fix.startsWith('0.000') && !fix.startsWith('-0.000')) {
        return fix;
      }

      // well, if it's still too long the user should've used longer numbers
      let exp = num.toExponential(len);
      if (exp.length > len) {
        exp = num.toExponential(Math.max(0, len - (exp.length - len)));
      }
      return exp.slice(0);
    }
    function installMathOperations(AbstractMatrix, Matrix) {
      AbstractMatrix.prototype.add = function add(value) {
        if (typeof value === 'number') return this.addS(value);
        return this.addM(value);
      };
      AbstractMatrix.prototype.addS = function addS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) + value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.addM = function addM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) + matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.add = function add(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.add(value);
      };
      AbstractMatrix.prototype.sub = function sub(value) {
        if (typeof value === 'number') return this.subS(value);
        return this.subM(value);
      };
      AbstractMatrix.prototype.subS = function subS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) - value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.subM = function subM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) - matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.sub = function sub(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.sub(value);
      };
      AbstractMatrix.prototype.subtract = AbstractMatrix.prototype.sub;
      AbstractMatrix.prototype.subtractS = AbstractMatrix.prototype.subS;
      AbstractMatrix.prototype.subtractM = AbstractMatrix.prototype.subM;
      AbstractMatrix.subtract = AbstractMatrix.sub;
      AbstractMatrix.prototype.mul = function mul(value) {
        if (typeof value === 'number') return this.mulS(value);
        return this.mulM(value);
      };
      AbstractMatrix.prototype.mulS = function mulS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) * value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.mulM = function mulM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) * matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.mul = function mul(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.mul(value);
      };
      AbstractMatrix.prototype.multiply = AbstractMatrix.prototype.mul;
      AbstractMatrix.prototype.multiplyS = AbstractMatrix.prototype.mulS;
      AbstractMatrix.prototype.multiplyM = AbstractMatrix.prototype.mulM;
      AbstractMatrix.multiply = AbstractMatrix.mul;
      AbstractMatrix.prototype.div = function div(value) {
        if (typeof value === 'number') return this.divS(value);
        return this.divM(value);
      };
      AbstractMatrix.prototype.divS = function divS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) / value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.divM = function divM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) / matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.div = function div(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.div(value);
      };
      AbstractMatrix.prototype.divide = AbstractMatrix.prototype.div;
      AbstractMatrix.prototype.divideS = AbstractMatrix.prototype.divS;
      AbstractMatrix.prototype.divideM = AbstractMatrix.prototype.divM;
      AbstractMatrix.divide = AbstractMatrix.div;
      AbstractMatrix.prototype.mod = function mod(value) {
        if (typeof value === 'number') return this.modS(value);
        return this.modM(value);
      };
      AbstractMatrix.prototype.modS = function modS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) % value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.modM = function modM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) % matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.mod = function mod(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.mod(value);
      };
      AbstractMatrix.prototype.modulus = AbstractMatrix.prototype.mod;
      AbstractMatrix.prototype.modulusS = AbstractMatrix.prototype.modS;
      AbstractMatrix.prototype.modulusM = AbstractMatrix.prototype.modM;
      AbstractMatrix.modulus = AbstractMatrix.mod;
      AbstractMatrix.prototype.and = function and(value) {
        if (typeof value === 'number') return this.andS(value);
        return this.andM(value);
      };
      AbstractMatrix.prototype.andS = function andS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) & value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.andM = function andM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) & matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.and = function and(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.and(value);
      };
      AbstractMatrix.prototype.or = function or(value) {
        if (typeof value === 'number') return this.orS(value);
        return this.orM(value);
      };
      AbstractMatrix.prototype.orS = function orS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) | value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.orM = function orM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) | matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.or = function or(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.or(value);
      };
      AbstractMatrix.prototype.xor = function xor(value) {
        if (typeof value === 'number') return this.xorS(value);
        return this.xorM(value);
      };
      AbstractMatrix.prototype.xorS = function xorS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) ^ value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.xorM = function xorM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) ^ matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.xor = function xor(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.xor(value);
      };
      AbstractMatrix.prototype.leftShift = function leftShift(value) {
        if (typeof value === 'number') return this.leftShiftS(value);
        return this.leftShiftM(value);
      };
      AbstractMatrix.prototype.leftShiftS = function leftShiftS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) << value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.leftShiftM = function leftShiftM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) << matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.leftShift = function leftShift(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.leftShift(value);
      };
      AbstractMatrix.prototype.signPropagatingRightShift = function signPropagatingRightShift(value) {
        if (typeof value === 'number') return this.signPropagatingRightShiftS(value);
        return this.signPropagatingRightShiftM(value);
      };
      AbstractMatrix.prototype.signPropagatingRightShiftS = function signPropagatingRightShiftS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) >> value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.signPropagatingRightShiftM = function signPropagatingRightShiftM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) >> matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.signPropagatingRightShift = function signPropagatingRightShift(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.signPropagatingRightShift(value);
      };
      AbstractMatrix.prototype.rightShift = function rightShift(value) {
        if (typeof value === 'number') return this.rightShiftS(value);
        return this.rightShiftM(value);
      };
      AbstractMatrix.prototype.rightShiftS = function rightShiftS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) >>> value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.rightShiftM = function rightShiftM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) >>> matrix.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.rightShift = function rightShift(matrix, value) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.rightShift(value);
      };
      AbstractMatrix.prototype.zeroFillRightShift = AbstractMatrix.prototype.rightShift;
      AbstractMatrix.prototype.zeroFillRightShiftS = AbstractMatrix.prototype.rightShiftS;
      AbstractMatrix.prototype.zeroFillRightShiftM = AbstractMatrix.prototype.rightShiftM;
      AbstractMatrix.zeroFillRightShift = AbstractMatrix.rightShift;
      AbstractMatrix.prototype.not = function not() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, ~this.get(i, j));
          }
        }
        return this;
      };
      AbstractMatrix.not = function not(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.not();
      };
      AbstractMatrix.prototype.abs = function abs() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.abs(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.abs = function abs(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.abs();
      };
      AbstractMatrix.prototype.acos = function acos() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.acos(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.acos = function acos(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.acos();
      };
      AbstractMatrix.prototype.acosh = function acosh() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.acosh(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.acosh = function acosh(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.acosh();
      };
      AbstractMatrix.prototype.asin = function asin() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.asin(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.asin = function asin(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.asin();
      };
      AbstractMatrix.prototype.asinh = function asinh() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.asinh(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.asinh = function asinh(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.asinh();
      };
      AbstractMatrix.prototype.atan = function atan() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.atan(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.atan = function atan(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.atan();
      };
      AbstractMatrix.prototype.atanh = function atanh() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.atanh(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.atanh = function atanh(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.atanh();
      };
      AbstractMatrix.prototype.cbrt = function cbrt() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.cbrt(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.cbrt = function cbrt(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.cbrt();
      };
      AbstractMatrix.prototype.ceil = function ceil() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.ceil(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.ceil = function ceil(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.ceil();
      };
      AbstractMatrix.prototype.clz32 = function clz32() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.clz32(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.clz32 = function clz32(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.clz32();
      };
      AbstractMatrix.prototype.cos = function cos() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.cos(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.cos = function cos(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.cos();
      };
      AbstractMatrix.prototype.cosh = function cosh() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.cosh(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.cosh = function cosh(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.cosh();
      };
      AbstractMatrix.prototype.exp = function exp() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.exp(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.exp = function exp(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.exp();
      };
      AbstractMatrix.prototype.expm1 = function expm1() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.expm1(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.expm1 = function expm1(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.expm1();
      };
      AbstractMatrix.prototype.floor = function floor() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.floor(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.floor = function floor(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.floor();
      };
      AbstractMatrix.prototype.fround = function fround() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.fround(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.fround = function fround(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.fround();
      };
      AbstractMatrix.prototype.log = function log() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.log(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.log = function log(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.log();
      };
      AbstractMatrix.prototype.log1p = function log1p() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.log1p(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.log1p = function log1p(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.log1p();
      };
      AbstractMatrix.prototype.log10 = function log10() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.log10(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.log10 = function log10(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.log10();
      };
      AbstractMatrix.prototype.log2 = function log2() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.log2(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.log2 = function log2(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.log2();
      };
      AbstractMatrix.prototype.round = function round() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.round(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.round = function round(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.round();
      };
      AbstractMatrix.prototype.sign = function sign() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.sign(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.sign = function sign(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.sign();
      };
      AbstractMatrix.prototype.sin = function sin() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.sin(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.sin = function sin(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.sin();
      };
      AbstractMatrix.prototype.sinh = function sinh() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.sinh(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.sinh = function sinh(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.sinh();
      };
      AbstractMatrix.prototype.sqrt = function sqrt() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.sqrt(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.sqrt = function sqrt(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.sqrt();
      };
      AbstractMatrix.prototype.tan = function tan() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.tan(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.tan = function tan(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.tan();
      };
      AbstractMatrix.prototype.tanh = function tanh() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.tanh(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.tanh = function tanh(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.tanh();
      };
      AbstractMatrix.prototype.trunc = function trunc() {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, Math.trunc(this.get(i, j)));
          }
        }
        return this;
      };
      AbstractMatrix.trunc = function trunc(matrix) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.trunc();
      };
      AbstractMatrix.pow = function pow(matrix, arg0) {
        const newMatrix = new Matrix(matrix);
        return newMatrix.pow(arg0);
      };
      AbstractMatrix.prototype.pow = function pow(value) {
        if (typeof value === 'number') return this.powS(value);
        return this.powM(value);
      };
      AbstractMatrix.prototype.powS = function powS(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) ** value);
          }
        }
        return this;
      };
      AbstractMatrix.prototype.powM = function powM(matrix) {
        matrix = Matrix.checkMatrix(matrix);
        if (this.rows !== matrix.rows || this.columns !== matrix.columns) {
          throw new RangeError('Matrices dimensions must be equal');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) ** matrix.get(i, j));
          }
        }
        return this;
      };
    }

    /**
     * @private
     * Check that a row index is not out of bounds
     * @param {Matrix} matrix
     * @param {number} index
     * @param {boolean} [outer]
     */
    function checkRowIndex(matrix, index, outer) {
      let max = outer ? matrix.rows : matrix.rows - 1;
      if (index < 0 || index > max) {
        throw new RangeError('Row index out of range');
      }
    }

    /**
     * @private
     * Check that a column index is not out of bounds
     * @param {Matrix} matrix
     * @param {number} index
     * @param {boolean} [outer]
     */
    function checkColumnIndex(matrix, index, outer) {
      let max = outer ? matrix.columns : matrix.columns - 1;
      if (index < 0 || index > max) {
        throw new RangeError('Column index out of range');
      }
    }

    /**
     * @private
     * Check that the provided vector is an array with the right length
     * @param {Matrix} matrix
     * @param {Array|Matrix} vector
     * @return {Array}
     * @throws {RangeError}
     */
    function checkRowVector(matrix, vector) {
      if (vector.to1DArray) {
        vector = vector.to1DArray();
      }
      if (vector.length !== matrix.columns) {
        throw new RangeError('vector size must be the same as the number of columns');
      }
      return vector;
    }

    /**
     * @private
     * Check that the provided vector is an array with the right length
     * @param {Matrix} matrix
     * @param {Array|Matrix} vector
     * @return {Array}
     * @throws {RangeError}
     */
    function checkColumnVector(matrix, vector) {
      if (vector.to1DArray) {
        vector = vector.to1DArray();
      }
      if (vector.length !== matrix.rows) {
        throw new RangeError('vector size must be the same as the number of rows');
      }
      return vector;
    }
    function checkRowIndices(matrix, rowIndices) {
      if (!isAnyArray.isAnyArray(rowIndices)) {
        throw new TypeError('row indices must be an array');
      }
      for (let i = 0; i < rowIndices.length; i++) {
        if (rowIndices[i] < 0 || rowIndices[i] >= matrix.rows) {
          throw new RangeError('row indices are out of range');
        }
      }
    }
    function checkColumnIndices(matrix, columnIndices) {
      if (!isAnyArray.isAnyArray(columnIndices)) {
        throw new TypeError('column indices must be an array');
      }
      for (let i = 0; i < columnIndices.length; i++) {
        if (columnIndices[i] < 0 || columnIndices[i] >= matrix.columns) {
          throw new RangeError('column indices are out of range');
        }
      }
    }
    function checkRange(matrix, startRow, endRow, startColumn, endColumn) {
      if (arguments.length !== 5) {
        throw new RangeError('expected 4 arguments');
      }
      checkNumber('startRow', startRow);
      checkNumber('endRow', endRow);
      checkNumber('startColumn', startColumn);
      checkNumber('endColumn', endColumn);
      if (startRow > endRow || startColumn > endColumn || startRow < 0 || startRow >= matrix.rows || endRow < 0 || endRow >= matrix.rows || startColumn < 0 || startColumn >= matrix.columns || endColumn < 0 || endColumn >= matrix.columns) {
        throw new RangeError('Submatrix indices are out of range');
      }
    }
    function newArray(length, value = 0) {
      let array = [];
      for (let i = 0; i < length; i++) {
        array.push(value);
      }
      return array;
    }
    function checkNumber(name, value) {
      if (typeof value !== 'number') {
        throw new TypeError(`${name} must be a number`);
      }
    }
    function checkNonEmpty(matrix) {
      if (matrix.isEmpty()) {
        throw new Error('Empty matrix has no elements to index');
      }
    }
    function sumByRow(matrix) {
      let sum = newArray(matrix.rows);
      for (let i = 0; i < matrix.rows; ++i) {
        for (let j = 0; j < matrix.columns; ++j) {
          sum[i] += matrix.get(i, j);
        }
      }
      return sum;
    }
    function sumByColumn(matrix) {
      let sum = newArray(matrix.columns);
      for (let i = 0; i < matrix.rows; ++i) {
        for (let j = 0; j < matrix.columns; ++j) {
          sum[j] += matrix.get(i, j);
        }
      }
      return sum;
    }
    function sumAll(matrix) {
      let v = 0;
      for (let i = 0; i < matrix.rows; i++) {
        for (let j = 0; j < matrix.columns; j++) {
          v += matrix.get(i, j);
        }
      }
      return v;
    }
    function productByRow(matrix) {
      let sum = newArray(matrix.rows, 1);
      for (let i = 0; i < matrix.rows; ++i) {
        for (let j = 0; j < matrix.columns; ++j) {
          sum[i] *= matrix.get(i, j);
        }
      }
      return sum;
    }
    function productByColumn(matrix) {
      let sum = newArray(matrix.columns, 1);
      for (let i = 0; i < matrix.rows; ++i) {
        for (let j = 0; j < matrix.columns; ++j) {
          sum[j] *= matrix.get(i, j);
        }
      }
      return sum;
    }
    function productAll(matrix) {
      let v = 1;
      for (let i = 0; i < matrix.rows; i++) {
        for (let j = 0; j < matrix.columns; j++) {
          v *= matrix.get(i, j);
        }
      }
      return v;
    }
    function varianceByRow(matrix, unbiased, mean) {
      const rows = matrix.rows;
      const cols = matrix.columns;
      const variance = [];
      for (let i = 0; i < rows; i++) {
        let sum1 = 0;
        let sum2 = 0;
        let x = 0;
        for (let j = 0; j < cols; j++) {
          x = matrix.get(i, j) - mean[i];
          sum1 += x;
          sum2 += x * x;
        }
        if (unbiased) {
          variance.push((sum2 - sum1 * sum1 / cols) / (cols - 1));
        } else {
          variance.push((sum2 - sum1 * sum1 / cols) / cols);
        }
      }
      return variance;
    }
    function varianceByColumn(matrix, unbiased, mean) {
      const rows = matrix.rows;
      const cols = matrix.columns;
      const variance = [];
      for (let j = 0; j < cols; j++) {
        let sum1 = 0;
        let sum2 = 0;
        let x = 0;
        for (let i = 0; i < rows; i++) {
          x = matrix.get(i, j) - mean[j];
          sum1 += x;
          sum2 += x * x;
        }
        if (unbiased) {
          variance.push((sum2 - sum1 * sum1 / rows) / (rows - 1));
        } else {
          variance.push((sum2 - sum1 * sum1 / rows) / rows);
        }
      }
      return variance;
    }
    function varianceAll(matrix, unbiased, mean) {
      const rows = matrix.rows;
      const cols = matrix.columns;
      const size = rows * cols;
      let sum1 = 0;
      let sum2 = 0;
      let x = 0;
      for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
          x = matrix.get(i, j) - mean;
          sum1 += x;
          sum2 += x * x;
        }
      }
      if (unbiased) {
        return (sum2 - sum1 * sum1 / size) / (size - 1);
      } else {
        return (sum2 - sum1 * sum1 / size) / size;
      }
    }
    function centerByRow(matrix, mean) {
      for (let i = 0; i < matrix.rows; i++) {
        for (let j = 0; j < matrix.columns; j++) {
          matrix.set(i, j, matrix.get(i, j) - mean[i]);
        }
      }
    }
    function centerByColumn(matrix, mean) {
      for (let i = 0; i < matrix.rows; i++) {
        for (let j = 0; j < matrix.columns; j++) {
          matrix.set(i, j, matrix.get(i, j) - mean[j]);
        }
      }
    }
    function centerAll(matrix, mean) {
      for (let i = 0; i < matrix.rows; i++) {
        for (let j = 0; j < matrix.columns; j++) {
          matrix.set(i, j, matrix.get(i, j) - mean);
        }
      }
    }
    function getScaleByRow(matrix) {
      const scale = [];
      for (let i = 0; i < matrix.rows; i++) {
        let sum = 0;
        for (let j = 0; j < matrix.columns; j++) {
          sum += matrix.get(i, j) ** 2 / (matrix.columns - 1);
        }
        scale.push(Math.sqrt(sum));
      }
      return scale;
    }
    function scaleByRow(matrix, scale) {
      for (let i = 0; i < matrix.rows; i++) {
        for (let j = 0; j < matrix.columns; j++) {
          matrix.set(i, j, matrix.get(i, j) / scale[i]);
        }
      }
    }
    function getScaleByColumn(matrix) {
      const scale = [];
      for (let j = 0; j < matrix.columns; j++) {
        let sum = 0;
        for (let i = 0; i < matrix.rows; i++) {
          sum += matrix.get(i, j) ** 2 / (matrix.rows - 1);
        }
        scale.push(Math.sqrt(sum));
      }
      return scale;
    }
    function scaleByColumn(matrix, scale) {
      for (let i = 0; i < matrix.rows; i++) {
        for (let j = 0; j < matrix.columns; j++) {
          matrix.set(i, j, matrix.get(i, j) / scale[j]);
        }
      }
    }
    function getScaleAll(matrix) {
      const divider = matrix.size - 1;
      let sum = 0;
      for (let j = 0; j < matrix.columns; j++) {
        for (let i = 0; i < matrix.rows; i++) {
          sum += matrix.get(i, j) ** 2 / divider;
        }
      }
      return Math.sqrt(sum);
    }
    function scaleAll(matrix, scale) {
      for (let i = 0; i < matrix.rows; i++) {
        for (let j = 0; j < matrix.columns; j++) {
          matrix.set(i, j, matrix.get(i, j) / scale);
        }
      }
    }
    class AbstractMatrix {
      static from1DArray(newRows, newColumns, newData) {
        let length = newRows * newColumns;
        if (length !== newData.length) {
          throw new RangeError('data length does not match given dimensions');
        }
        let newMatrix = new Matrix$1(newRows, newColumns);
        for (let row = 0; row < newRows; row++) {
          for (let column = 0; column < newColumns; column++) {
            newMatrix.set(row, column, newData[row * newColumns + column]);
          }
        }
        return newMatrix;
      }
      static rowVector(newData) {
        let vector = new Matrix$1(1, newData.length);
        for (let i = 0; i < newData.length; i++) {
          vector.set(0, i, newData[i]);
        }
        return vector;
      }
      static columnVector(newData) {
        let vector = new Matrix$1(newData.length, 1);
        for (let i = 0; i < newData.length; i++) {
          vector.set(i, 0, newData[i]);
        }
        return vector;
      }
      static zeros(rows, columns) {
        return new Matrix$1(rows, columns);
      }
      static ones(rows, columns) {
        return new Matrix$1(rows, columns).fill(1);
      }
      static rand(rows, columns, options = {}) {
        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }
        const {
          random = Math.random
        } = options;
        let matrix = new Matrix$1(rows, columns);
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < columns; j++) {
            matrix.set(i, j, random());
          }
        }
        return matrix;
      }
      static randInt(rows, columns, options = {}) {
        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }
        const {
          min = 0,
          max = 1000,
          random = Math.random
        } = options;
        if (!Number.isInteger(min)) throw new TypeError('min must be an integer');
        if (!Number.isInteger(max)) throw new TypeError('max must be an integer');
        if (min >= max) throw new RangeError('min must be smaller than max');
        let interval = max - min;
        let matrix = new Matrix$1(rows, columns);
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < columns; j++) {
            let value = min + Math.round(random() * interval);
            matrix.set(i, j, value);
          }
        }
        return matrix;
      }
      static eye(rows, columns, value) {
        if (columns === undefined) columns = rows;
        if (value === undefined) value = 1;
        let min = Math.min(rows, columns);
        let matrix = this.zeros(rows, columns);
        for (let i = 0; i < min; i++) {
          matrix.set(i, i, value);
        }
        return matrix;
      }
      static diag(data, rows, columns) {
        let l = data.length;
        if (rows === undefined) rows = l;
        if (columns === undefined) columns = rows;
        let min = Math.min(l, rows, columns);
        let matrix = this.zeros(rows, columns);
        for (let i = 0; i < min; i++) {
          matrix.set(i, i, data[i]);
        }
        return matrix;
      }
      static min(matrix1, matrix2) {
        matrix1 = this.checkMatrix(matrix1);
        matrix2 = this.checkMatrix(matrix2);
        let rows = matrix1.rows;
        let columns = matrix1.columns;
        let result = new Matrix$1(rows, columns);
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < columns; j++) {
            result.set(i, j, Math.min(matrix1.get(i, j), matrix2.get(i, j)));
          }
        }
        return result;
      }
      static max(matrix1, matrix2) {
        matrix1 = this.checkMatrix(matrix1);
        matrix2 = this.checkMatrix(matrix2);
        let rows = matrix1.rows;
        let columns = matrix1.columns;
        let result = new this(rows, columns);
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < columns; j++) {
            result.set(i, j, Math.max(matrix1.get(i, j), matrix2.get(i, j)));
          }
        }
        return result;
      }
      static checkMatrix(value) {
        return AbstractMatrix.isMatrix(value) ? value : new Matrix$1(value);
      }
      static isMatrix(value) {
        return value != null && value.klass === 'Matrix';
      }
      get size() {
        return this.rows * this.columns;
      }
      apply(callback) {
        if (typeof callback !== 'function') {
          throw new TypeError('callback must be a function');
        }
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            callback.call(this, i, j);
          }
        }
        return this;
      }
      to1DArray() {
        let array = [];
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            array.push(this.get(i, j));
          }
        }
        return array;
      }
      to2DArray() {
        let copy = [];
        for (let i = 0; i < this.rows; i++) {
          copy.push([]);
          for (let j = 0; j < this.columns; j++) {
            copy[i].push(this.get(i, j));
          }
        }
        return copy;
      }
      toJSON() {
        return this.to2DArray();
      }
      isRowVector() {
        return this.rows === 1;
      }
      isColumnVector() {
        return this.columns === 1;
      }
      isVector() {
        return this.rows === 1 || this.columns === 1;
      }
      isSquare() {
        return this.rows === this.columns;
      }
      isEmpty() {
        return this.rows === 0 || this.columns === 0;
      }
      isSymmetric() {
        if (this.isSquare()) {
          for (let i = 0; i < this.rows; i++) {
            for (let j = 0; j <= i; j++) {
              if (this.get(i, j) !== this.get(j, i)) {
                return false;
              }
            }
          }
          return true;
        }
        return false;
      }
      isDistance() {
        if (!this.isSymmetric()) return false;
        for (let i = 0; i < this.rows; i++) {
          if (this.get(i, i) !== 0) return false;
        }
        return true;
      }
      isEchelonForm() {
        let i = 0;
        let j = 0;
        let previousColumn = -1;
        let isEchelonForm = true;
        let checked = false;
        while (i < this.rows && isEchelonForm) {
          j = 0;
          checked = false;
          while (j < this.columns && checked === false) {
            if (this.get(i, j) === 0) {
              j++;
            } else if (this.get(i, j) === 1 && j > previousColumn) {
              checked = true;
              previousColumn = j;
            } else {
              isEchelonForm = false;
              checked = true;
            }
          }
          i++;
        }
        return isEchelonForm;
      }
      isReducedEchelonForm() {
        let i = 0;
        let j = 0;
        let previousColumn = -1;
        let isReducedEchelonForm = true;
        let checked = false;
        while (i < this.rows && isReducedEchelonForm) {
          j = 0;
          checked = false;
          while (j < this.columns && checked === false) {
            if (this.get(i, j) === 0) {
              j++;
            } else if (this.get(i, j) === 1 && j > previousColumn) {
              checked = true;
              previousColumn = j;
            } else {
              isReducedEchelonForm = false;
              checked = true;
            }
          }
          for (let k = j + 1; k < this.rows; k++) {
            if (this.get(i, k) !== 0) {
              isReducedEchelonForm = false;
            }
          }
          i++;
        }
        return isReducedEchelonForm;
      }
      echelonForm() {
        let result = this.clone();
        let h = 0;
        let k = 0;
        while (h < result.rows && k < result.columns) {
          let iMax = h;
          for (let i = h; i < result.rows; i++) {
            if (result.get(i, k) > result.get(iMax, k)) {
              iMax = i;
            }
          }
          if (result.get(iMax, k) === 0) {
            k++;
          } else {
            result.swapRows(h, iMax);
            let tmp = result.get(h, k);
            for (let j = k; j < result.columns; j++) {
              result.set(h, j, result.get(h, j) / tmp);
            }
            for (let i = h + 1; i < result.rows; i++) {
              let factor = result.get(i, k) / result.get(h, k);
              result.set(i, k, 0);
              for (let j = k + 1; j < result.columns; j++) {
                result.set(i, j, result.get(i, j) - result.get(h, j) * factor);
              }
            }
            h++;
            k++;
          }
        }
        return result;
      }
      reducedEchelonForm() {
        let result = this.echelonForm();
        let m = result.columns;
        let n = result.rows;
        let h = n - 1;
        while (h >= 0) {
          if (result.maxRow(h) === 0) {
            h--;
          } else {
            let p = 0;
            let pivot = false;
            while (p < n && pivot === false) {
              if (result.get(h, p) === 1) {
                pivot = true;
              } else {
                p++;
              }
            }
            for (let i = 0; i < h; i++) {
              let factor = result.get(i, p);
              for (let j = p; j < m; j++) {
                let tmp = result.get(i, j) - factor * result.get(h, j);
                result.set(i, j, tmp);
              }
            }
            h--;
          }
        }
        return result;
      }
      set() {
        throw new Error('set method is unimplemented');
      }
      get() {
        throw new Error('get method is unimplemented');
      }
      repeat(options = {}) {
        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }
        const {
          rows = 1,
          columns = 1
        } = options;
        if (!Number.isInteger(rows) || rows <= 0) {
          throw new TypeError('rows must be a positive integer');
        }
        if (!Number.isInteger(columns) || columns <= 0) {
          throw new TypeError('columns must be a positive integer');
        }
        let matrix = new Matrix$1(this.rows * rows, this.columns * columns);
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < columns; j++) {
            matrix.setSubMatrix(this, this.rows * i, this.columns * j);
          }
        }
        return matrix;
      }
      fill(value) {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, value);
          }
        }
        return this;
      }
      neg() {
        return this.mulS(-1);
      }
      getRow(index) {
        checkRowIndex(this, index);
        let row = [];
        for (let i = 0; i < this.columns; i++) {
          row.push(this.get(index, i));
        }
        return row;
      }
      getRowVector(index) {
        return Matrix$1.rowVector(this.getRow(index));
      }
      setRow(index, array) {
        checkRowIndex(this, index);
        array = checkRowVector(this, array);
        for (let i = 0; i < this.columns; i++) {
          this.set(index, i, array[i]);
        }
        return this;
      }
      swapRows(row1, row2) {
        checkRowIndex(this, row1);
        checkRowIndex(this, row2);
        for (let i = 0; i < this.columns; i++) {
          let temp = this.get(row1, i);
          this.set(row1, i, this.get(row2, i));
          this.set(row2, i, temp);
        }
        return this;
      }
      getColumn(index) {
        checkColumnIndex(this, index);
        let column = [];
        for (let i = 0; i < this.rows; i++) {
          column.push(this.get(i, index));
        }
        return column;
      }
      getColumnVector(index) {
        return Matrix$1.columnVector(this.getColumn(index));
      }
      setColumn(index, array) {
        checkColumnIndex(this, index);
        array = checkColumnVector(this, array);
        for (let i = 0; i < this.rows; i++) {
          this.set(i, index, array[i]);
        }
        return this;
      }
      swapColumns(column1, column2) {
        checkColumnIndex(this, column1);
        checkColumnIndex(this, column2);
        for (let i = 0; i < this.rows; i++) {
          let temp = this.get(i, column1);
          this.set(i, column1, this.get(i, column2));
          this.set(i, column2, temp);
        }
        return this;
      }
      addRowVector(vector) {
        vector = checkRowVector(this, vector);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) + vector[j]);
          }
        }
        return this;
      }
      subRowVector(vector) {
        vector = checkRowVector(this, vector);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) - vector[j]);
          }
        }
        return this;
      }
      mulRowVector(vector) {
        vector = checkRowVector(this, vector);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) * vector[j]);
          }
        }
        return this;
      }
      divRowVector(vector) {
        vector = checkRowVector(this, vector);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) / vector[j]);
          }
        }
        return this;
      }
      addColumnVector(vector) {
        vector = checkColumnVector(this, vector);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) + vector[i]);
          }
        }
        return this;
      }
      subColumnVector(vector) {
        vector = checkColumnVector(this, vector);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) - vector[i]);
          }
        }
        return this;
      }
      mulColumnVector(vector) {
        vector = checkColumnVector(this, vector);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) * vector[i]);
          }
        }
        return this;
      }
      divColumnVector(vector) {
        vector = checkColumnVector(this, vector);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            this.set(i, j, this.get(i, j) / vector[i]);
          }
        }
        return this;
      }
      mulRow(index, value) {
        checkRowIndex(this, index);
        for (let i = 0; i < this.columns; i++) {
          this.set(index, i, this.get(index, i) * value);
        }
        return this;
      }
      mulColumn(index, value) {
        checkColumnIndex(this, index);
        for (let i = 0; i < this.rows; i++) {
          this.set(i, index, this.get(i, index) * value);
        }
        return this;
      }
      max(by) {
        if (this.isEmpty()) {
          return NaN;
        }
        switch (by) {
          case 'row':
            {
              const max = new Array(this.rows).fill(Number.NEGATIVE_INFINITY);
              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) > max[row]) {
                    max[row] = this.get(row, column);
                  }
                }
              }
              return max;
            }
          case 'column':
            {
              const max = new Array(this.columns).fill(Number.NEGATIVE_INFINITY);
              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) > max[column]) {
                    max[column] = this.get(row, column);
                  }
                }
              }
              return max;
            }
          case undefined:
            {
              let max = this.get(0, 0);
              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) > max) {
                    max = this.get(row, column);
                  }
                }
              }
              return max;
            }
          default:
            throw new Error(`invalid option: ${by}`);
        }
      }
      maxIndex() {
        checkNonEmpty(this);
        let v = this.get(0, 0);
        let idx = [0, 0];
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            if (this.get(i, j) > v) {
              v = this.get(i, j);
              idx[0] = i;
              idx[1] = j;
            }
          }
        }
        return idx;
      }
      min(by) {
        if (this.isEmpty()) {
          return NaN;
        }
        switch (by) {
          case 'row':
            {
              const min = new Array(this.rows).fill(Number.POSITIVE_INFINITY);
              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) < min[row]) {
                    min[row] = this.get(row, column);
                  }
                }
              }
              return min;
            }
          case 'column':
            {
              const min = new Array(this.columns).fill(Number.POSITIVE_INFINITY);
              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) < min[column]) {
                    min[column] = this.get(row, column);
                  }
                }
              }
              return min;
            }
          case undefined:
            {
              let min = this.get(0, 0);
              for (let row = 0; row < this.rows; row++) {
                for (let column = 0; column < this.columns; column++) {
                  if (this.get(row, column) < min) {
                    min = this.get(row, column);
                  }
                }
              }
              return min;
            }
          default:
            throw new Error(`invalid option: ${by}`);
        }
      }
      minIndex() {
        checkNonEmpty(this);
        let v = this.get(0, 0);
        let idx = [0, 0];
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            if (this.get(i, j) < v) {
              v = this.get(i, j);
              idx[0] = i;
              idx[1] = j;
            }
          }
        }
        return idx;
      }
      maxRow(row) {
        checkRowIndex(this, row);
        if (this.isEmpty()) {
          return NaN;
        }
        let v = this.get(row, 0);
        for (let i = 1; i < this.columns; i++) {
          if (this.get(row, i) > v) {
            v = this.get(row, i);
          }
        }
        return v;
      }
      maxRowIndex(row) {
        checkRowIndex(this, row);
        checkNonEmpty(this);
        let v = this.get(row, 0);
        let idx = [row, 0];
        for (let i = 1; i < this.columns; i++) {
          if (this.get(row, i) > v) {
            v = this.get(row, i);
            idx[1] = i;
          }
        }
        return idx;
      }
      minRow(row) {
        checkRowIndex(this, row);
        if (this.isEmpty()) {
          return NaN;
        }
        let v = this.get(row, 0);
        for (let i = 1; i < this.columns; i++) {
          if (this.get(row, i) < v) {
            v = this.get(row, i);
          }
        }
        return v;
      }
      minRowIndex(row) {
        checkRowIndex(this, row);
        checkNonEmpty(this);
        let v = this.get(row, 0);
        let idx = [row, 0];
        for (let i = 1; i < this.columns; i++) {
          if (this.get(row, i) < v) {
            v = this.get(row, i);
            idx[1] = i;
          }
        }
        return idx;
      }
      maxColumn(column) {
        checkColumnIndex(this, column);
        if (this.isEmpty()) {
          return NaN;
        }
        let v = this.get(0, column);
        for (let i = 1; i < this.rows; i++) {
          if (this.get(i, column) > v) {
            v = this.get(i, column);
          }
        }
        return v;
      }
      maxColumnIndex(column) {
        checkColumnIndex(this, column);
        checkNonEmpty(this);
        let v = this.get(0, column);
        let idx = [0, column];
        for (let i = 1; i < this.rows; i++) {
          if (this.get(i, column) > v) {
            v = this.get(i, column);
            idx[0] = i;
          }
        }
        return idx;
      }
      minColumn(column) {
        checkColumnIndex(this, column);
        if (this.isEmpty()) {
          return NaN;
        }
        let v = this.get(0, column);
        for (let i = 1; i < this.rows; i++) {
          if (this.get(i, column) < v) {
            v = this.get(i, column);
          }
        }
        return v;
      }
      minColumnIndex(column) {
        checkColumnIndex(this, column);
        checkNonEmpty(this);
        let v = this.get(0, column);
        let idx = [0, column];
        for (let i = 1; i < this.rows; i++) {
          if (this.get(i, column) < v) {
            v = this.get(i, column);
            idx[0] = i;
          }
        }
        return idx;
      }
      diag() {
        let min = Math.min(this.rows, this.columns);
        let diag = [];
        for (let i = 0; i < min; i++) {
          diag.push(this.get(i, i));
        }
        return diag;
      }
      norm(type = 'frobenius') {
        switch (type) {
          case 'max':
            return this.max();
          case 'frobenius':
            return Math.sqrt(this.dot(this));
          default:
            throw new RangeError(`unknown norm type: ${type}`);
        }
      }
      cumulativeSum() {
        let sum = 0;
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            sum += this.get(i, j);
            this.set(i, j, sum);
          }
        }
        return this;
      }
      dot(vector2) {
        if (AbstractMatrix.isMatrix(vector2)) vector2 = vector2.to1DArray();
        let vector1 = this.to1DArray();
        if (vector1.length !== vector2.length) {
          throw new RangeError('vectors do not have the same size');
        }
        let dot = 0;
        for (let i = 0; i < vector1.length; i++) {
          dot += vector1[i] * vector2[i];
        }
        return dot;
      }
      mmul(other) {
        other = Matrix$1.checkMatrix(other);
        let m = this.rows;
        let n = this.columns;
        let p = other.columns;
        let result = new Matrix$1(m, p);
        let Bcolj = new Float64Array(n);
        for (let j = 0; j < p; j++) {
          for (let k = 0; k < n; k++) {
            Bcolj[k] = other.get(k, j);
          }
          for (let i = 0; i < m; i++) {
            let s = 0;
            for (let k = 0; k < n; k++) {
              s += this.get(i, k) * Bcolj[k];
            }
            result.set(i, j, s);
          }
        }
        return result;
      }
      mpow(scalar) {
        if (!this.isSquare()) {
          throw new RangeError('Matrix must be square');
        }
        if (!Number.isInteger(scalar) || scalar < 0) {
          throw new RangeError('Exponent must be a non-negative integer');
        }
        // Russian Peasant exponentiation, i.e. exponentiation by squaring
        let result = Matrix$1.eye(this.rows);
        let bb = this;
        // Note: Don't bit shift. In JS, that would truncate at 32 bits
        for (let e = scalar; e >= 1; e /= 2) {
          if ((e & 1) !== 0) {
            result = result.mmul(bb);
          }
          bb = bb.mmul(bb);
        }
        return result;
      }
      strassen2x2(other) {
        other = Matrix$1.checkMatrix(other);
        let result = new Matrix$1(2, 2);
        const a11 = this.get(0, 0);
        const b11 = other.get(0, 0);
        const a12 = this.get(0, 1);
        const b12 = other.get(0, 1);
        const a21 = this.get(1, 0);
        const b21 = other.get(1, 0);
        const a22 = this.get(1, 1);
        const b22 = other.get(1, 1);

        // Compute intermediate values.
        const m1 = (a11 + a22) * (b11 + b22);
        const m2 = (a21 + a22) * b11;
        const m3 = a11 * (b12 - b22);
        const m4 = a22 * (b21 - b11);
        const m5 = (a11 + a12) * b22;
        const m6 = (a21 - a11) * (b11 + b12);
        const m7 = (a12 - a22) * (b21 + b22);

        // Combine intermediate values into the output.
        const c00 = m1 + m4 - m5 + m7;
        const c01 = m3 + m5;
        const c10 = m2 + m4;
        const c11 = m1 - m2 + m3 + m6;
        result.set(0, 0, c00);
        result.set(0, 1, c01);
        result.set(1, 0, c10);
        result.set(1, 1, c11);
        return result;
      }
      strassen3x3(other) {
        other = Matrix$1.checkMatrix(other);
        let result = new Matrix$1(3, 3);
        const a00 = this.get(0, 0);
        const a01 = this.get(0, 1);
        const a02 = this.get(0, 2);
        const a10 = this.get(1, 0);
        const a11 = this.get(1, 1);
        const a12 = this.get(1, 2);
        const a20 = this.get(2, 0);
        const a21 = this.get(2, 1);
        const a22 = this.get(2, 2);
        const b00 = other.get(0, 0);
        const b01 = other.get(0, 1);
        const b02 = other.get(0, 2);
        const b10 = other.get(1, 0);
        const b11 = other.get(1, 1);
        const b12 = other.get(1, 2);
        const b20 = other.get(2, 0);
        const b21 = other.get(2, 1);
        const b22 = other.get(2, 2);
        const m1 = (a00 + a01 + a02 - a10 - a11 - a21 - a22) * b11;
        const m2 = (a00 - a10) * (-b01 + b11);
        const m3 = a11 * (-b00 + b01 + b10 - b11 - b12 - b20 + b22);
        const m4 = (-a00 + a10 + a11) * (b00 - b01 + b11);
        const m5 = (a10 + a11) * (-b00 + b01);
        const m6 = a00 * b00;
        const m7 = (-a00 + a20 + a21) * (b00 - b02 + b12);
        const m8 = (-a00 + a20) * (b02 - b12);
        const m9 = (a20 + a21) * (-b00 + b02);
        const m10 = (a00 + a01 + a02 - a11 - a12 - a20 - a21) * b12;
        const m11 = a21 * (-b00 + b02 + b10 - b11 - b12 - b20 + b21);
        const m12 = (-a02 + a21 + a22) * (b11 + b20 - b21);
        const m13 = (a02 - a22) * (b11 - b21);
        const m14 = a02 * b20;
        const m15 = (a21 + a22) * (-b20 + b21);
        const m16 = (-a02 + a11 + a12) * (b12 + b20 - b22);
        const m17 = (a02 - a12) * (b12 - b22);
        const m18 = (a11 + a12) * (-b20 + b22);
        const m19 = a01 * b10;
        const m20 = a12 * b21;
        const m21 = a10 * b02;
        const m22 = a20 * b01;
        const m23 = a22 * b22;
        const c00 = m6 + m14 + m19;
        const c01 = m1 + m4 + m5 + m6 + m12 + m14 + m15;
        const c02 = m6 + m7 + m9 + m10 + m14 + m16 + m18;
        const c10 = m2 + m3 + m4 + m6 + m14 + m16 + m17;
        const c11 = m2 + m4 + m5 + m6 + m20;
        const c12 = m14 + m16 + m17 + m18 + m21;
        const c20 = m6 + m7 + m8 + m11 + m12 + m13 + m14;
        const c21 = m12 + m13 + m14 + m15 + m22;
        const c22 = m6 + m7 + m8 + m9 + m23;
        result.set(0, 0, c00);
        result.set(0, 1, c01);
        result.set(0, 2, c02);
        result.set(1, 0, c10);
        result.set(1, 1, c11);
        result.set(1, 2, c12);
        result.set(2, 0, c20);
        result.set(2, 1, c21);
        result.set(2, 2, c22);
        return result;
      }
      mmulStrassen(y) {
        y = Matrix$1.checkMatrix(y);
        let x = this.clone();
        let r1 = x.rows;
        let c1 = x.columns;
        let r2 = y.rows;
        let c2 = y.columns;
        if (c1 !== r2) {
          // eslint-disable-next-line no-console
          console.warn(`Multiplying ${r1} x ${c1} and ${r2} x ${c2} matrix: dimensions do not match.`);
        }

        // Put a matrix into the top left of a matrix of zeros.
        // `rows` and `cols` are the dimensions of the output matrix.
        function embed(mat, rows, cols) {
          let r = mat.rows;
          let c = mat.columns;
          if (r === rows && c === cols) {
            return mat;
          } else {
            let resultat = AbstractMatrix.zeros(rows, cols);
            resultat = resultat.setSubMatrix(mat, 0, 0);
            return resultat;
          }
        }

        // Make sure both matrices are the same size.
        // This is exclusively for simplicity:
        // this algorithm can be implemented with matrices of different sizes.

        let r = Math.max(r1, r2);
        let c = Math.max(c1, c2);
        x = embed(x, r, c);
        y = embed(y, r, c);

        // Our recursive multiplication function.
        function blockMult(a, b, rows, cols) {
          // For small matrices, resort to naive multiplication.
          if (rows <= 512 || cols <= 512) {
            return a.mmul(b); // a is equivalent to this
          }

          // Apply dynamic padding.
          if (rows % 2 === 1 && cols % 2 === 1) {
            a = embed(a, rows + 1, cols + 1);
            b = embed(b, rows + 1, cols + 1);
          } else if (rows % 2 === 1) {
            a = embed(a, rows + 1, cols);
            b = embed(b, rows + 1, cols);
          } else if (cols % 2 === 1) {
            a = embed(a, rows, cols + 1);
            b = embed(b, rows, cols + 1);
          }
          let halfRows = parseInt(a.rows / 2, 10);
          let halfCols = parseInt(a.columns / 2, 10);
          // Subdivide input matrices.
          let a11 = a.subMatrix(0, halfRows - 1, 0, halfCols - 1);
          let b11 = b.subMatrix(0, halfRows - 1, 0, halfCols - 1);
          let a12 = a.subMatrix(0, halfRows - 1, halfCols, a.columns - 1);
          let b12 = b.subMatrix(0, halfRows - 1, halfCols, b.columns - 1);
          let a21 = a.subMatrix(halfRows, a.rows - 1, 0, halfCols - 1);
          let b21 = b.subMatrix(halfRows, b.rows - 1, 0, halfCols - 1);
          let a22 = a.subMatrix(halfRows, a.rows - 1, halfCols, a.columns - 1);
          let b22 = b.subMatrix(halfRows, b.rows - 1, halfCols, b.columns - 1);

          // Compute intermediate values.
          let m1 = blockMult(AbstractMatrix.add(a11, a22), AbstractMatrix.add(b11, b22), halfRows, halfCols);
          let m2 = blockMult(AbstractMatrix.add(a21, a22), b11, halfRows, halfCols);
          let m3 = blockMult(a11, AbstractMatrix.sub(b12, b22), halfRows, halfCols);
          let m4 = blockMult(a22, AbstractMatrix.sub(b21, b11), halfRows, halfCols);
          let m5 = blockMult(AbstractMatrix.add(a11, a12), b22, halfRows, halfCols);
          let m6 = blockMult(AbstractMatrix.sub(a21, a11), AbstractMatrix.add(b11, b12), halfRows, halfCols);
          let m7 = blockMult(AbstractMatrix.sub(a12, a22), AbstractMatrix.add(b21, b22), halfRows, halfCols);

          // Combine intermediate values into the output.
          let c11 = AbstractMatrix.add(m1, m4);
          c11.sub(m5);
          c11.add(m7);
          let c12 = AbstractMatrix.add(m3, m5);
          let c21 = AbstractMatrix.add(m2, m4);
          let c22 = AbstractMatrix.sub(m1, m2);
          c22.add(m3);
          c22.add(m6);

          // Crop output to the desired size (undo dynamic padding).
          let result = AbstractMatrix.zeros(2 * c11.rows, 2 * c11.columns);
          result = result.setSubMatrix(c11, 0, 0);
          result = result.setSubMatrix(c12, c11.rows, 0);
          result = result.setSubMatrix(c21, 0, c11.columns);
          result = result.setSubMatrix(c22, c11.rows, c11.columns);
          return result.subMatrix(0, rows - 1, 0, cols - 1);
        }
        return blockMult(x, y, r, c);
      }
      scaleRows(options = {}) {
        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }
        const {
          min = 0,
          max = 1
        } = options;
        if (!Number.isFinite(min)) throw new TypeError('min must be a number');
        if (!Number.isFinite(max)) throw new TypeError('max must be a number');
        if (min >= max) throw new RangeError('min must be smaller than max');
        let newMatrix = new Matrix$1(this.rows, this.columns);
        for (let i = 0; i < this.rows; i++) {
          const row = this.getRow(i);
          if (row.length > 0) {
            rescale$1(row, {
              min,
              max,
              output: row
            });
          }
          newMatrix.setRow(i, row);
        }
        return newMatrix;
      }
      scaleColumns(options = {}) {
        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }
        const {
          min = 0,
          max = 1
        } = options;
        if (!Number.isFinite(min)) throw new TypeError('min must be a number');
        if (!Number.isFinite(max)) throw new TypeError('max must be a number');
        if (min >= max) throw new RangeError('min must be smaller than max');
        let newMatrix = new Matrix$1(this.rows, this.columns);
        for (let i = 0; i < this.columns; i++) {
          const column = this.getColumn(i);
          if (column.length) {
            rescale$1(column, {
              min,
              max,
              output: column
            });
          }
          newMatrix.setColumn(i, column);
        }
        return newMatrix;
      }
      flipRows() {
        const middle = Math.ceil(this.columns / 2);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < middle; j++) {
            let first = this.get(i, j);
            let last = this.get(i, this.columns - 1 - j);
            this.set(i, j, last);
            this.set(i, this.columns - 1 - j, first);
          }
        }
        return this;
      }
      flipColumns() {
        const middle = Math.ceil(this.rows / 2);
        for (let j = 0; j < this.columns; j++) {
          for (let i = 0; i < middle; i++) {
            let first = this.get(i, j);
            let last = this.get(this.rows - 1 - i, j);
            this.set(i, j, last);
            this.set(this.rows - 1 - i, j, first);
          }
        }
        return this;
      }
      kroneckerProduct(other) {
        other = Matrix$1.checkMatrix(other);
        let m = this.rows;
        let n = this.columns;
        let p = other.rows;
        let q = other.columns;
        let result = new Matrix$1(m * p, n * q);
        for (let i = 0; i < m; i++) {
          for (let j = 0; j < n; j++) {
            for (let k = 0; k < p; k++) {
              for (let l = 0; l < q; l++) {
                result.set(p * i + k, q * j + l, this.get(i, j) * other.get(k, l));
              }
            }
          }
        }
        return result;
      }
      kroneckerSum(other) {
        other = Matrix$1.checkMatrix(other);
        if (!this.isSquare() || !other.isSquare()) {
          throw new Error('Kronecker Sum needs two Square Matrices');
        }
        let m = this.rows;
        let n = other.rows;
        let AxI = this.kroneckerProduct(Matrix$1.eye(n, n));
        let IxB = Matrix$1.eye(m, m).kroneckerProduct(other);
        return AxI.add(IxB);
      }
      transpose() {
        let result = new Matrix$1(this.columns, this.rows);
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            result.set(j, i, this.get(i, j));
          }
        }
        return result;
      }
      sortRows(compareFunction = compareNumbers) {
        for (let i = 0; i < this.rows; i++) {
          this.setRow(i, this.getRow(i).sort(compareFunction));
        }
        return this;
      }
      sortColumns(compareFunction = compareNumbers) {
        for (let i = 0; i < this.columns; i++) {
          this.setColumn(i, this.getColumn(i).sort(compareFunction));
        }
        return this;
      }
      subMatrix(startRow, endRow, startColumn, endColumn) {
        checkRange(this, startRow, endRow, startColumn, endColumn);
        let newMatrix = new Matrix$1(endRow - startRow + 1, endColumn - startColumn + 1);
        for (let i = startRow; i <= endRow; i++) {
          for (let j = startColumn; j <= endColumn; j++) {
            newMatrix.set(i - startRow, j - startColumn, this.get(i, j));
          }
        }
        return newMatrix;
      }
      subMatrixRow(indices, startColumn, endColumn) {
        if (startColumn === undefined) startColumn = 0;
        if (endColumn === undefined) endColumn = this.columns - 1;
        if (startColumn > endColumn || startColumn < 0 || startColumn >= this.columns || endColumn < 0 || endColumn >= this.columns) {
          throw new RangeError('Argument out of range');
        }
        let newMatrix = new Matrix$1(indices.length, endColumn - startColumn + 1);
        for (let i = 0; i < indices.length; i++) {
          for (let j = startColumn; j <= endColumn; j++) {
            if (indices[i] < 0 || indices[i] >= this.rows) {
              throw new RangeError(`Row index out of range: ${indices[i]}`);
            }
            newMatrix.set(i, j - startColumn, this.get(indices[i], j));
          }
        }
        return newMatrix;
      }
      subMatrixColumn(indices, startRow, endRow) {
        if (startRow === undefined) startRow = 0;
        if (endRow === undefined) endRow = this.rows - 1;
        if (startRow > endRow || startRow < 0 || startRow >= this.rows || endRow < 0 || endRow >= this.rows) {
          throw new RangeError('Argument out of range');
        }
        let newMatrix = new Matrix$1(endRow - startRow + 1, indices.length);
        for (let i = 0; i < indices.length; i++) {
          for (let j = startRow; j <= endRow; j++) {
            if (indices[i] < 0 || indices[i] >= this.columns) {
              throw new RangeError(`Column index out of range: ${indices[i]}`);
            }
            newMatrix.set(j - startRow, i, this.get(j, indices[i]));
          }
        }
        return newMatrix;
      }
      setSubMatrix(matrix, startRow, startColumn) {
        matrix = Matrix$1.checkMatrix(matrix);
        if (matrix.isEmpty()) {
          return this;
        }
        let endRow = startRow + matrix.rows - 1;
        let endColumn = startColumn + matrix.columns - 1;
        checkRange(this, startRow, endRow, startColumn, endColumn);
        for (let i = 0; i < matrix.rows; i++) {
          for (let j = 0; j < matrix.columns; j++) {
            this.set(startRow + i, startColumn + j, matrix.get(i, j));
          }
        }
        return this;
      }
      selection(rowIndices, columnIndices) {
        checkRowIndices(this, rowIndices);
        checkColumnIndices(this, columnIndices);
        let newMatrix = new Matrix$1(rowIndices.length, columnIndices.length);
        for (let i = 0; i < rowIndices.length; i++) {
          let rowIndex = rowIndices[i];
          for (let j = 0; j < columnIndices.length; j++) {
            let columnIndex = columnIndices[j];
            newMatrix.set(i, j, this.get(rowIndex, columnIndex));
          }
        }
        return newMatrix;
      }
      trace() {
        let min = Math.min(this.rows, this.columns);
        let trace = 0;
        for (let i = 0; i < min; i++) {
          trace += this.get(i, i);
        }
        return trace;
      }
      clone() {
        return this.constructor.copy(this, new Matrix$1(this.rows, this.columns));
      }

      /**
       * @template {AbstractMatrix} M
       * @param {AbstractMatrix} from
       * @param {M} to
       * @return {M}
       */
      static copy(from, to) {
        for (const [row, column, value] of from.entries()) {
          to.set(row, column, value);
        }
        return to;
      }
      sum(by) {
        switch (by) {
          case 'row':
            return sumByRow(this);
          case 'column':
            return sumByColumn(this);
          case undefined:
            return sumAll(this);
          default:
            throw new Error(`invalid option: ${by}`);
        }
      }
      product(by) {
        switch (by) {
          case 'row':
            return productByRow(this);
          case 'column':
            return productByColumn(this);
          case undefined:
            return productAll(this);
          default:
            throw new Error(`invalid option: ${by}`);
        }
      }
      mean(by) {
        const sum = this.sum(by);
        switch (by) {
          case 'row':
            {
              for (let i = 0; i < this.rows; i++) {
                sum[i] /= this.columns;
              }
              return sum;
            }
          case 'column':
            {
              for (let i = 0; i < this.columns; i++) {
                sum[i] /= this.rows;
              }
              return sum;
            }
          case undefined:
            return sum / this.size;
          default:
            throw new Error(`invalid option: ${by}`);
        }
      }
      variance(by, options = {}) {
        if (typeof by === 'object') {
          options = by;
          by = undefined;
        }
        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }
        const {
          unbiased = true,
          mean = this.mean(by)
        } = options;
        if (typeof unbiased !== 'boolean') {
          throw new TypeError('unbiased must be a boolean');
        }
        switch (by) {
          case 'row':
            {
              if (!isAnyArray.isAnyArray(mean)) {
                throw new TypeError('mean must be an array');
              }
              return varianceByRow(this, unbiased, mean);
            }
          case 'column':
            {
              if (!isAnyArray.isAnyArray(mean)) {
                throw new TypeError('mean must be an array');
              }
              return varianceByColumn(this, unbiased, mean);
            }
          case undefined:
            {
              if (typeof mean !== 'number') {
                throw new TypeError('mean must be a number');
              }
              return varianceAll(this, unbiased, mean);
            }
          default:
            throw new Error(`invalid option: ${by}`);
        }
      }
      standardDeviation(by, options) {
        if (typeof by === 'object') {
          options = by;
          by = undefined;
        }
        const variance = this.variance(by, options);
        if (by === undefined) {
          return Math.sqrt(variance);
        } else {
          for (let i = 0; i < variance.length; i++) {
            variance[i] = Math.sqrt(variance[i]);
          }
          return variance;
        }
      }
      center(by, options = {}) {
        if (typeof by === 'object') {
          options = by;
          by = undefined;
        }
        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }
        const {
          center = this.mean(by)
        } = options;
        switch (by) {
          case 'row':
            {
              if (!isAnyArray.isAnyArray(center)) {
                throw new TypeError('center must be an array');
              }
              centerByRow(this, center);
              return this;
            }
          case 'column':
            {
              if (!isAnyArray.isAnyArray(center)) {
                throw new TypeError('center must be an array');
              }
              centerByColumn(this, center);
              return this;
            }
          case undefined:
            {
              if (typeof center !== 'number') {
                throw new TypeError('center must be a number');
              }
              centerAll(this, center);
              return this;
            }
          default:
            throw new Error(`invalid option: ${by}`);
        }
      }
      scale(by, options = {}) {
        if (typeof by === 'object') {
          options = by;
          by = undefined;
        }
        if (typeof options !== 'object') {
          throw new TypeError('options must be an object');
        }
        let scale = options.scale;
        switch (by) {
          case 'row':
            {
              if (scale === undefined) {
                scale = getScaleByRow(this);
              } else if (!isAnyArray.isAnyArray(scale)) {
                throw new TypeError('scale must be an array');
              }
              scaleByRow(this, scale);
              return this;
            }
          case 'column':
            {
              if (scale === undefined) {
                scale = getScaleByColumn(this);
              } else if (!isAnyArray.isAnyArray(scale)) {
                throw new TypeError('scale must be an array');
              }
              scaleByColumn(this, scale);
              return this;
            }
          case undefined:
            {
              if (scale === undefined) {
                scale = getScaleAll(this);
              } else if (typeof scale !== 'number') {
                throw new TypeError('scale must be a number');
              }
              scaleAll(this, scale);
              return this;
            }
          default:
            throw new Error(`invalid option: ${by}`);
        }
      }
      toString(options) {
        return inspectMatrixWithOptions(this, options);
      }
      [Symbol.iterator]() {
        return this.entries();
      }

      /**
       * iterator from left to right, from top to bottom
       * yield [row, column, value]
       * @returns {Generator<[number, number, number], void, void>}
       */
      *entries() {
        for (let row = 0; row < this.rows; row++) {
          for (let col = 0; col < this.columns; col++) {
            yield [row, col, this.get(row, col)];
          }
        }
      }

      /**
       * iterator from left to right, from top to bottom
       * yield value
       * @returns {Generator<number, void, void>}
       */
      *values() {
        for (let row = 0; row < this.rows; row++) {
          for (let col = 0; col < this.columns; col++) {
            yield this.get(row, col);
          }
        }
      }
    }
    AbstractMatrix.prototype.klass = 'Matrix';
    if (typeof Symbol !== 'undefined') {
      AbstractMatrix.prototype[Symbol.for('nodejs.util.inspect.custom')] = inspectMatrix;
    }
    function compareNumbers(a, b) {
      return a - b;
    }
    function isArrayOfNumbers(array) {
      return array.every(element => {
        return typeof element === 'number';
      });
    }

    // Synonyms
    AbstractMatrix.random = AbstractMatrix.rand;
    AbstractMatrix.randomInt = AbstractMatrix.randInt;
    AbstractMatrix.diagonal = AbstractMatrix.diag;
    AbstractMatrix.prototype.diagonal = AbstractMatrix.prototype.diag;
    AbstractMatrix.identity = AbstractMatrix.eye;
    AbstractMatrix.prototype.negate = AbstractMatrix.prototype.neg;
    AbstractMatrix.prototype.tensorProduct = AbstractMatrix.prototype.kroneckerProduct;
    let Matrix$1 = class Matrix extends AbstractMatrix {
      /**
       * @type {Float64Array[]}
       */
      data;

      /**
       * Init an empty matrix
       * @param {number} nRows
       * @param {number} nColumns
       */
      #initData(nRows, nColumns) {
        this.data = [];
        if (Number.isInteger(nColumns) && nColumns >= 0) {
          for (let i = 0; i < nRows; i++) {
            this.data.push(new Float64Array(nColumns));
          }
        } else {
          throw new TypeError('nColumns must be a positive integer');
        }
        this.rows = nRows;
        this.columns = nColumns;
      }
      constructor(nRows, nColumns) {
        super();
        if (Matrix.isMatrix(nRows)) {
          this.#initData(nRows.rows, nRows.columns);
          Matrix.copy(nRows, this);
        } else if (Number.isInteger(nRows) && nRows >= 0) {
          this.#initData(nRows, nColumns);
        } else if (isAnyArray.isAnyArray(nRows)) {
          // Copy the values from the 2D array
          const arrayData = nRows;
          nRows = arrayData.length;
          nColumns = nRows ? arrayData[0].length : 0;
          if (typeof nColumns !== 'number') {
            throw new TypeError('Data must be a 2D array with at least one element');
          }
          this.data = [];
          for (let i = 0; i < nRows; i++) {
            if (arrayData[i].length !== nColumns) {
              throw new RangeError('Inconsistent array dimensions');
            }
            if (!isArrayOfNumbers(arrayData[i])) {
              throw new TypeError('Input data contains non-numeric values');
            }
            this.data.push(Float64Array.from(arrayData[i]));
          }
          this.rows = nRows;
          this.columns = nColumns;
        } else {
          throw new TypeError('First argument must be a positive number or an array');
        }
      }
      set(rowIndex, columnIndex, value) {
        this.data[rowIndex][columnIndex] = value;
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.data[rowIndex][columnIndex];
      }
      removeRow(index) {
        checkRowIndex(this, index);
        this.data.splice(index, 1);
        this.rows -= 1;
        return this;
      }
      addRow(index, array) {
        if (array === undefined) {
          array = index;
          index = this.rows;
        }
        checkRowIndex(this, index, true);
        array = Float64Array.from(checkRowVector(this, array));
        this.data.splice(index, 0, array);
        this.rows += 1;
        return this;
      }
      removeColumn(index) {
        checkColumnIndex(this, index);
        for (let i = 0; i < this.rows; i++) {
          const newRow = new Float64Array(this.columns - 1);
          for (let j = 0; j < index; j++) {
            newRow[j] = this.data[i][j];
          }
          for (let j = index + 1; j < this.columns; j++) {
            newRow[j - 1] = this.data[i][j];
          }
          this.data[i] = newRow;
        }
        this.columns -= 1;
        return this;
      }
      addColumn(index, array) {
        if (typeof array === 'undefined') {
          array = index;
          index = this.columns;
        }
        checkColumnIndex(this, index, true);
        array = checkColumnVector(this, array);
        for (let i = 0; i < this.rows; i++) {
          const newRow = new Float64Array(this.columns + 1);
          let j = 0;
          for (; j < index; j++) {
            newRow[j] = this.data[i][j];
          }
          newRow[j++] = array[i];
          for (; j < this.columns + 1; j++) {
            newRow[j] = this.data[i][j - 1];
          }
          this.data[i] = newRow;
        }
        this.columns += 1;
        return this;
      }
    };
    installMathOperations(AbstractMatrix, Matrix$1);

    /**
     * @typedef {0 | 1 | number | boolean} Mask
     */

    class SymmetricMatrix extends AbstractMatrix {
      /** @type {Matrix} */
      #matrix;
      get size() {
        return this.#matrix.size;
      }
      get rows() {
        return this.#matrix.rows;
      }
      get columns() {
        return this.#matrix.columns;
      }
      get diagonalSize() {
        return this.rows;
      }

      /**
       * not the same as matrix.isSymmetric()
       * Here is to check if it's instanceof SymmetricMatrix without bundling issues
       *
       * @param value
       * @returns {boolean}
       */
      static isSymmetricMatrix(value) {
        return Matrix$1.isMatrix(value) && value.klassType === 'SymmetricMatrix';
      }

      /**
       * @param diagonalSize
       * @return {SymmetricMatrix}
       */
      static zeros(diagonalSize) {
        return new this(diagonalSize);
      }

      /**
       * @param diagonalSize
       * @return {SymmetricMatrix}
       */
      static ones(diagonalSize) {
        return new this(diagonalSize).fill(1);
      }

      /**
       * @param {number | AbstractMatrix | ArrayLike<ArrayLike<number>>} diagonalSize
       * @return {this}
       */
      constructor(diagonalSize) {
        super();
        if (Matrix$1.isMatrix(diagonalSize)) {
          if (!diagonalSize.isSymmetric()) {
            throw new TypeError('not symmetric data');
          }
          this.#matrix = Matrix$1.copy(diagonalSize, new Matrix$1(diagonalSize.rows, diagonalSize.rows));
        } else if (Number.isInteger(diagonalSize) && diagonalSize >= 0) {
          this.#matrix = new Matrix$1(diagonalSize, diagonalSize);
        } else {
          this.#matrix = new Matrix$1(diagonalSize);
          if (!this.isSymmetric()) {
            throw new TypeError('not symmetric data');
          }
        }
      }
      clone() {
        const matrix = new SymmetricMatrix(this.diagonalSize);
        for (const [row, col, value] of this.upperRightEntries()) {
          matrix.set(row, col, value);
        }
        return matrix;
      }
      toMatrix() {
        return new Matrix$1(this);
      }
      get(rowIndex, columnIndex) {
        return this.#matrix.get(rowIndex, columnIndex);
      }
      set(rowIndex, columnIndex, value) {
        // symmetric set
        this.#matrix.set(rowIndex, columnIndex, value);
        this.#matrix.set(columnIndex, rowIndex, value);
        return this;
      }
      removeCross(index) {
        // symmetric remove side
        this.#matrix.removeRow(index);
        this.#matrix.removeColumn(index);
        return this;
      }
      addCross(index, array) {
        if (array === undefined) {
          array = index;
          index = this.diagonalSize;
        }
        const row = array.slice();
        row.splice(index, 1);
        this.#matrix.addRow(index, row);
        this.#matrix.addColumn(index, array);
        return this;
      }

      /**
       * @param {Mask[]} mask
       */
      applyMask(mask) {
        if (mask.length !== this.diagonalSize) {
          throw new RangeError('Mask size do not match with matrix size');
        }

        // prepare sides to remove from matrix from mask
        /** @type {number[]} */
        const sidesToRemove = [];
        for (const [index, passthroughs] of mask.entries()) {
          if (passthroughs) continue;
          sidesToRemove.push(index);
        }
        // to remove from highest to lowest for no mutation shifting
        sidesToRemove.reverse();

        // remove sides
        for (const sideIndex of sidesToRemove) {
          this.removeCross(sideIndex);
        }
        return this;
      }

      /**
       * Compact format upper-right corner of matrix
       * iterate from left to right, from top to bottom.
       *
       * ```
       *   A B C D
       * A 1 2 3 4
       * B 2 5 6 7
       * C 3 6 8 9
       * D 4 7 9 10
       * ```
       *
       * will return compact 1D array `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`
       *
       * length is S(i=0, n=sideSize) => 10 for a 4 sideSized matrix
       *
       * @returns {number[]}
       */
      toCompact() {
        const {
          diagonalSize
        } = this;

        /** @type {number[]} */
        const compact = new Array(diagonalSize * (diagonalSize + 1) / 2);
        for (let col = 0, row = 0, index = 0; index < compact.length; index++) {
          compact[index] = this.get(row, col);
          if (++col >= diagonalSize) col = ++row;
        }
        return compact;
      }

      /**
       * @param {number[]} compact
       * @return {SymmetricMatrix}
       */
      static fromCompact(compact) {
        const compactSize = compact.length;
        // compactSize = (sideSize * (sideSize + 1)) / 2
        // https://mathsolver.microsoft.com/fr/solve-problem/y%20%3D%20%20x%20%60cdot%20%20%20%60frac%7B%20%20%60left(%20x%2B1%20%20%60right)%20%20%20%20%7D%7B%202%20%20%7D
        // sideSize = (Sqrt(8 × compactSize + 1) - 1) / 2
        const diagonalSize = (Math.sqrt(8 * compactSize + 1) - 1) / 2;
        if (!Number.isInteger(diagonalSize)) {
          throw new TypeError(`This array is not a compact representation of a Symmetric Matrix, ${JSON.stringify(compact)}`);
        }
        const matrix = new SymmetricMatrix(diagonalSize);
        for (let col = 0, row = 0, index = 0; index < compactSize; index++) {
          matrix.set(col, row, compact[index]);
          if (++col >= diagonalSize) col = ++row;
        }
        return matrix;
      }

      /**
       * half iterator upper-right-corner from left to right, from top to bottom
       * yield [row, column, value]
       *
       * @returns {Generator<[number, number, number], void, void>}
       */
      *upperRightEntries() {
        for (let row = 0, col = 0; row < this.diagonalSize; void 0) {
          const value = this.get(row, col);
          yield [row, col, value];

          // at the end of row, move cursor to next row at diagonal position
          if (++col >= this.diagonalSize) col = ++row;
        }
      }

      /**
       * half iterator upper-right-corner from left to right, from top to bottom
       * yield value
       *
       * @returns {Generator<[number, number, number], void, void>}
       */
      *upperRightValues() {
        for (let row = 0, col = 0; row < this.diagonalSize; void 0) {
          const value = this.get(row, col);
          yield value;

          // at the end of row, move cursor to next row at diagonal position
          if (++col >= this.diagonalSize) col = ++row;
        }
      }
    }
    SymmetricMatrix.prototype.klassType = 'SymmetricMatrix';
    class DistanceMatrix extends SymmetricMatrix {
      /**
       * not the same as matrix.isSymmetric()
       * Here is to check if it's instanceof SymmetricMatrix without bundling issues
       *
       * @param value
       * @returns {boolean}
       */
      static isDistanceMatrix(value) {
        return SymmetricMatrix.isSymmetricMatrix(value) && value.klassSubType === 'DistanceMatrix';
      }
      constructor(sideSize) {
        super(sideSize);
        if (!this.isDistance()) {
          throw new TypeError('Provided arguments do no produce a distance matrix');
        }
      }
      set(rowIndex, columnIndex, value) {
        // distance matrix diagonal is 0
        if (rowIndex === columnIndex) value = 0;
        return super.set(rowIndex, columnIndex, value);
      }
      addCross(index, array) {
        if (array === undefined) {
          array = index;
          index = this.diagonalSize;
        }

        // ensure distance
        array = array.slice();
        array[index] = 0;
        return super.addCross(index, array);
      }
      toSymmetricMatrix() {
        return new SymmetricMatrix(this);
      }
      clone() {
        const matrix = new DistanceMatrix(this.diagonalSize);
        for (const [row, col, value] of this.upperRightEntries()) {
          if (row === col) continue;
          matrix.set(row, col, value);
        }
        return matrix;
      }

      /**
       * Compact format upper-right corner of matrix
       * no diagonal (only zeros)
       * iterable from left to right, from top to bottom.
       *
       * ```
       *   A B C D
       * A 0 1 2 3
       * B 1 0 4 5
       * C 2 4 0 6
       * D 3 5 6 0
       * ```
       *
       * will return compact 1D array `[1, 2, 3, 4, 5, 6]`
       *
       * length is S(i=0, n=sideSize-1) => 6 for a 4 side sized matrix
       *
       * @returns {number[]}
       */
      toCompact() {
        const {
          diagonalSize
        } = this;
        const compactLength = (diagonalSize - 1) * diagonalSize / 2;

        /** @type {number[]} */
        const compact = new Array(compactLength);
        for (let col = 1, row = 0, index = 0; index < compact.length; index++) {
          compact[index] = this.get(row, col);
          if (++col >= diagonalSize) col = ++row + 1;
        }
        return compact;
      }

      /**
       * @param {number[]} compact
       */
      static fromCompact(compact) {
        const compactSize = compact.length;
        if (compactSize === 0) {
          return new this(0);
        }

        // compactSize in Natural integer range ]0;∞]
        // compactSize = (sideSize * (sideSize - 1)) / 2
        // sideSize = (Sqrt(8 × compactSize + 1) + 1) / 2
        const diagonalSize = (Math.sqrt(8 * compactSize + 1) + 1) / 2;
        if (!Number.isInteger(diagonalSize)) {
          throw new TypeError(`This array is not a compact representation of a DistanceMatrix, ${JSON.stringify(compact)}`);
        }
        const matrix = new this(diagonalSize);
        for (let col = 1, row = 0, index = 0; index < compactSize; index++) {
          matrix.set(col, row, compact[index]);
          if (++col >= diagonalSize) col = ++row + 1;
        }
        return matrix;
      }
    }
    DistanceMatrix.prototype.klassSubType = 'DistanceMatrix';
    class BaseView extends AbstractMatrix {
      constructor(matrix, rows, columns) {
        super();
        this.matrix = matrix;
        this.rows = rows;
        this.columns = columns;
      }
    }
    class MatrixColumnView extends BaseView {
      constructor(matrix, column) {
        checkColumnIndex(matrix, column);
        super(matrix, matrix.rows, 1);
        this.column = column;
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(rowIndex, this.column, value);
        return this;
      }
      get(rowIndex) {
        return this.matrix.get(rowIndex, this.column);
      }
    }
    class MatrixColumnSelectionView extends BaseView {
      constructor(matrix, columnIndices) {
        checkColumnIndices(matrix, columnIndices);
        super(matrix, matrix.rows, columnIndices.length);
        this.columnIndices = columnIndices;
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(rowIndex, this.columnIndices[columnIndex], value);
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.matrix.get(rowIndex, this.columnIndices[columnIndex]);
      }
    }
    class MatrixFlipColumnView extends BaseView {
      constructor(matrix) {
        super(matrix, matrix.rows, matrix.columns);
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(rowIndex, this.columns - columnIndex - 1, value);
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.matrix.get(rowIndex, this.columns - columnIndex - 1);
      }
    }
    class MatrixFlipRowView extends BaseView {
      constructor(matrix) {
        super(matrix, matrix.rows, matrix.columns);
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(this.rows - rowIndex - 1, columnIndex, value);
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.matrix.get(this.rows - rowIndex - 1, columnIndex);
      }
    }
    class MatrixRowView extends BaseView {
      constructor(matrix, row) {
        checkRowIndex(matrix, row);
        super(matrix, 1, matrix.columns);
        this.row = row;
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(this.row, columnIndex, value);
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.matrix.get(this.row, columnIndex);
      }
    }
    class MatrixRowSelectionView extends BaseView {
      constructor(matrix, rowIndices) {
        checkRowIndices(matrix, rowIndices);
        super(matrix, rowIndices.length, matrix.columns);
        this.rowIndices = rowIndices;
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(this.rowIndices[rowIndex], columnIndex, value);
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.matrix.get(this.rowIndices[rowIndex], columnIndex);
      }
    }
    class MatrixSelectionView extends BaseView {
      constructor(matrix, rowIndices, columnIndices) {
        checkRowIndices(matrix, rowIndices);
        checkColumnIndices(matrix, columnIndices);
        super(matrix, rowIndices.length, columnIndices.length);
        this.rowIndices = rowIndices;
        this.columnIndices = columnIndices;
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(this.rowIndices[rowIndex], this.columnIndices[columnIndex], value);
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.matrix.get(this.rowIndices[rowIndex], this.columnIndices[columnIndex]);
      }
    }
    class MatrixSubView extends BaseView {
      constructor(matrix, startRow, endRow, startColumn, endColumn) {
        checkRange(matrix, startRow, endRow, startColumn, endColumn);
        super(matrix, endRow - startRow + 1, endColumn - startColumn + 1);
        this.startRow = startRow;
        this.startColumn = startColumn;
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(this.startRow + rowIndex, this.startColumn + columnIndex, value);
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.matrix.get(this.startRow + rowIndex, this.startColumn + columnIndex);
      }
    }
    let MatrixTransposeView$1 = class MatrixTransposeView extends BaseView {
      constructor(matrix) {
        super(matrix, matrix.columns, matrix.rows);
      }
      set(rowIndex, columnIndex, value) {
        this.matrix.set(columnIndex, rowIndex, value);
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.matrix.get(columnIndex, rowIndex);
      }
    };
    class WrapperMatrix1D extends AbstractMatrix {
      constructor(data, options = {}) {
        const {
          rows = 1
        } = options;
        if (data.length % rows !== 0) {
          throw new Error('the data length is not divisible by the number of rows');
        }
        super();
        this.rows = rows;
        this.columns = data.length / rows;
        this.data = data;
      }
      set(rowIndex, columnIndex, value) {
        let index = this._calculateIndex(rowIndex, columnIndex);
        this.data[index] = value;
        return this;
      }
      get(rowIndex, columnIndex) {
        let index = this._calculateIndex(rowIndex, columnIndex);
        return this.data[index];
      }
      _calculateIndex(row, column) {
        return row * this.columns + column;
      }
    }
    class WrapperMatrix2D extends AbstractMatrix {
      constructor(data) {
        super();
        this.data = data;
        this.rows = data.length;
        this.columns = data[0].length;
      }
      set(rowIndex, columnIndex, value) {
        this.data[rowIndex][columnIndex] = value;
        return this;
      }
      get(rowIndex, columnIndex) {
        return this.data[rowIndex][columnIndex];
      }
    }
    function wrap(array, options) {
      if (isAnyArray.isAnyArray(array)) {
        if (array[0] && isAnyArray.isAnyArray(array[0])) {
          return new WrapperMatrix2D(array);
        } else {
          return new WrapperMatrix1D(array, options);
        }
      } else {
        throw new Error('the argument is not an array');
      }
    }
    class LuDecomposition {
      constructor(matrix) {
        matrix = WrapperMatrix2D.checkMatrix(matrix);
        let lu = matrix.clone();
        let rows = lu.rows;
        let columns = lu.columns;
        let pivotVector = new Float64Array(rows);
        let pivotSign = 1;
        let i, j, k, p, s, t, v;
        let LUcolj, kmax;
        for (i = 0; i < rows; i++) {
          pivotVector[i] = i;
        }
        LUcolj = new Float64Array(rows);
        for (j = 0; j < columns; j++) {
          for (i = 0; i < rows; i++) {
            LUcolj[i] = lu.get(i, j);
          }
          for (i = 0; i < rows; i++) {
            kmax = Math.min(i, j);
            s = 0;
            for (k = 0; k < kmax; k++) {
              s += lu.get(i, k) * LUcolj[k];
            }
            LUcolj[i] -= s;
            lu.set(i, j, LUcolj[i]);
          }
          p = j;
          for (i = j + 1; i < rows; i++) {
            if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) {
              p = i;
            }
          }
          if (p !== j) {
            for (k = 0; k < columns; k++) {
              t = lu.get(p, k);
              lu.set(p, k, lu.get(j, k));
              lu.set(j, k, t);
            }
            v = pivotVector[p];
            pivotVector[p] = pivotVector[j];
            pivotVector[j] = v;
            pivotSign = -pivotSign;
          }
          if (j < rows && lu.get(j, j) !== 0) {
            for (i = j + 1; i < rows; i++) {
              lu.set(i, j, lu.get(i, j) / lu.get(j, j));
            }
          }
        }
        this.LU = lu;
        this.pivotVector = pivotVector;
        this.pivotSign = pivotSign;
      }
      isSingular() {
        let data = this.LU;
        let col = data.columns;
        for (let j = 0; j < col; j++) {
          if (data.get(j, j) === 0) {
            return true;
          }
        }
        return false;
      }
      solve(value) {
        value = Matrix$1.checkMatrix(value);
        let lu = this.LU;
        let rows = lu.rows;
        if (rows !== value.rows) {
          throw new Error('Invalid matrix dimensions');
        }
        if (this.isSingular()) {
          throw new Error('LU matrix is singular');
        }
        let count = value.columns;
        let X = value.subMatrixRow(this.pivotVector, 0, count - 1);
        let columns = lu.columns;
        let i, j, k;
        for (k = 0; k < columns; k++) {
          for (i = k + 1; i < columns; i++) {
            for (j = 0; j < count; j++) {
              X.set(i, j, X.get(i, j) - X.get(k, j) * lu.get(i, k));
            }
          }
        }
        for (k = columns - 1; k >= 0; k--) {
          for (j = 0; j < count; j++) {
            X.set(k, j, X.get(k, j) / lu.get(k, k));
          }
          for (i = 0; i < k; i++) {
            for (j = 0; j < count; j++) {
              X.set(i, j, X.get(i, j) - X.get(k, j) * lu.get(i, k));
            }
          }
        }
        return X;
      }
      get determinant() {
        let data = this.LU;
        if (!data.isSquare()) {
          throw new Error('Matrix must be square');
        }
        let determinant = this.pivotSign;
        let col = data.columns;
        for (let j = 0; j < col; j++) {
          determinant *= data.get(j, j);
        }
        return determinant;
      }
      get lowerTriangularMatrix() {
        let data = this.LU;
        let rows = data.rows;
        let columns = data.columns;
        let X = new Matrix$1(rows, columns);
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < columns; j++) {
            if (i > j) {
              X.set(i, j, data.get(i, j));
            } else if (i === j) {
              X.set(i, j, 1);
            } else {
              X.set(i, j, 0);
            }
          }
        }
        return X;
      }
      get upperTriangularMatrix() {
        let data = this.LU;
        let rows = data.rows;
        let columns = data.columns;
        let X = new Matrix$1(rows, columns);
        for (let i = 0; i < rows; i++) {
          for (let j = 0; j < columns; j++) {
            if (i <= j) {
              X.set(i, j, data.get(i, j));
            } else {
              X.set(i, j, 0);
            }
          }
        }
        return X;
      }
      get pivotPermutationVector() {
        return Array.from(this.pivotVector);
      }
    }
    function hypotenuse(a, b) {
      let r = 0;
      if (Math.abs(a) > Math.abs(b)) {
        r = b / a;
        return Math.abs(a) * Math.sqrt(1 + r * r);
      }
      if (b !== 0) {
        r = a / b;
        return Math.abs(b) * Math.sqrt(1 + r * r);
      }
      return 0;
    }
    class QrDecomposition {
      constructor(value) {
        value = WrapperMatrix2D.checkMatrix(value);
        let qr = value.clone();
        let m = value.rows;
        let n = value.columns;
        let rdiag = new Float64Array(n);
        let i, j, k, s;
        for (k = 0; k < n; k++) {
          let nrm = 0;
          for (i = k; i < m; i++) {
            nrm = hypotenuse(nrm, qr.get(i, k));
          }
          if (nrm !== 0) {
            if (qr.get(k, k) < 0) {
              nrm = -nrm;
            }
            for (i = k; i < m; i++) {
              qr.set(i, k, qr.get(i, k) / nrm);
            }
            qr.set(k, k, qr.get(k, k) + 1);
            for (j = k + 1; j < n; j++) {
              s = 0;
              for (i = k; i < m; i++) {
                s += qr.get(i, k) * qr.get(i, j);
              }
              s = -s / qr.get(k, k);
              for (i = k; i < m; i++) {
                qr.set(i, j, qr.get(i, j) + s * qr.get(i, k));
              }
            }
          }
          rdiag[k] = -nrm;
        }
        this.QR = qr;
        this.Rdiag = rdiag;
      }
      solve(value) {
        value = Matrix$1.checkMatrix(value);
        let qr = this.QR;
        let m = qr.rows;
        if (value.rows !== m) {
          throw new Error('Matrix row dimensions must agree');
        }
        if (!this.isFullRank()) {
          throw new Error('Matrix is rank deficient');
        }
        let count = value.columns;
        let X = value.clone();
        let n = qr.columns;
        let i, j, k, s;
        for (k = 0; k < n; k++) {
          for (j = 0; j < count; j++) {
            s = 0;
            for (i = k; i < m; i++) {
              s += qr.get(i, k) * X.get(i, j);
            }
            s = -s / qr.get(k, k);
            for (i = k; i < m; i++) {
              X.set(i, j, X.get(i, j) + s * qr.get(i, k));
            }
          }
        }
        for (k = n - 1; k >= 0; k--) {
          for (j = 0; j < count; j++) {
            X.set(k, j, X.get(k, j) / this.Rdiag[k]);
          }
          for (i = 0; i < k; i++) {
            for (j = 0; j < count; j++) {
              X.set(i, j, X.get(i, j) - X.get(k, j) * qr.get(i, k));
            }
          }
        }
        return X.subMatrix(0, n - 1, 0, count - 1);
      }
      isFullRank() {
        let columns = this.QR.columns;
        for (let i = 0; i < columns; i++) {
          if (this.Rdiag[i] === 0) {
            return false;
          }
        }
        return true;
      }
      get upperTriangularMatrix() {
        let qr = this.QR;
        let n = qr.columns;
        let X = new Matrix$1(n, n);
        let i, j;
        for (i = 0; i < n; i++) {
          for (j = 0; j < n; j++) {
            if (i < j) {
              X.set(i, j, qr.get(i, j));
            } else if (i === j) {
              X.set(i, j, this.Rdiag[i]);
            } else {
              X.set(i, j, 0);
            }
          }
        }
        return X;
      }
      get orthogonalMatrix() {
        let qr = this.QR;
        let rows = qr.rows;
        let columns = qr.columns;
        let X = new Matrix$1(rows, columns);
        let i, j, k, s;
        for (k = columns - 1; k >= 0; k--) {
          for (i = 0; i < rows; i++) {
            X.set(i, k, 0);
          }
          X.set(k, k, 1);
          for (j = k; j < columns; j++) {
            if (qr.get(k, k) !== 0) {
              s = 0;
              for (i = k; i < rows; i++) {
                s += qr.get(i, k) * X.get(i, j);
              }
              s = -s / qr.get(k, k);
              for (i = k; i < rows; i++) {
                X.set(i, j, X.get(i, j) + s * qr.get(i, k));
              }
            }
          }
        }
        return X;
      }
    }
    class SingularValueDecomposition {
      constructor(value, options = {}) {
        value = WrapperMatrix2D.checkMatrix(value);
        if (value.isEmpty()) {
          throw new Error('Matrix must be non-empty');
        }
        let m = value.rows;
        let n = value.columns;
        const {
          computeLeftSingularVectors = true,
          computeRightSingularVectors = true,
          autoTranspose = false
        } = options;
        let wantu = Boolean(computeLeftSingularVectors);
        let wantv = Boolean(computeRightSingularVectors);
        let swapped = false;
        let a;
        if (m < n) {
          if (!autoTranspose) {
            a = value.clone();
            // eslint-disable-next-line no-console
            console.warn('Computing SVD on a matrix with more columns than rows. Consider enabling autoTranspose');
          } else {
            a = value.transpose();
            m = a.rows;
            n = a.columns;
            swapped = true;
            let aux = wantu;
            wantu = wantv;
            wantv = aux;
          }
        } else {
          a = value.clone();
        }
        let nu = Math.min(m, n);
        let ni = Math.min(m + 1, n);
        let s = new Float64Array(ni);
        let U = new Matrix$1(m, nu);
        let V = new Matrix$1(n, n);
        let e = new Float64Array(n);
        let work = new Float64Array(m);
        let si = new Float64Array(ni);
        for (let i = 0; i < ni; i++) si[i] = i;
        let nct = Math.min(m - 1, n);
        let nrt = Math.max(0, Math.min(n - 2, m));
        let mrc = Math.max(nct, nrt);
        for (let k = 0; k < mrc; k++) {
          if (k < nct) {
            s[k] = 0;
            for (let i = k; i < m; i++) {
              s[k] = hypotenuse(s[k], a.get(i, k));
            }
            if (s[k] !== 0) {
              if (a.get(k, k) < 0) {
                s[k] = -s[k];
              }
              for (let i = k; i < m; i++) {
                a.set(i, k, a.get(i, k) / s[k]);
              }
              a.set(k, k, a.get(k, k) + 1);
            }
            s[k] = -s[k];
          }
          for (let j = k + 1; j < n; j++) {
            if (k < nct && s[k] !== 0) {
              let t = 0;
              for (let i = k; i < m; i++) {
                t += a.get(i, k) * a.get(i, j);
              }
              t = -t / a.get(k, k);
              for (let i = k; i < m; i++) {
                a.set(i, j, a.get(i, j) + t * a.get(i, k));
              }
            }
            e[j] = a.get(k, j);
          }
          if (wantu && k < nct) {
            for (let i = k; i < m; i++) {
              U.set(i, k, a.get(i, k));
            }
          }
          if (k < nrt) {
            e[k] = 0;
            for (let i = k + 1; i < n; i++) {
              e[k] = hypotenuse(e[k], e[i]);
            }
            if (e[k] !== 0) {
              if (e[k + 1] < 0) {
                e[k] = 0 - e[k];
              }
              for (let i = k + 1; i < n; i++) {
                e[i] /= e[k];
              }
              e[k + 1] += 1;
            }
            e[k] = -e[k];
            if (k + 1 < m && e[k] !== 0) {
              for (let i = k + 1; i < m; i++) {
                work[i] = 0;
              }
              for (let i = k + 1; i < m; i++) {
                for (let j = k + 1; j < n; j++) {
                  work[i] += e[j] * a.get(i, j);
                }
              }
              for (let j = k + 1; j < n; j++) {
                let t = -e[j] / e[k + 1];
                for (let i = k + 1; i < m; i++) {
                  a.set(i, j, a.get(i, j) + t * work[i]);
                }
              }
            }
            if (wantv) {
              for (let i = k + 1; i < n; i++) {
                V.set(i, k, e[i]);
              }
            }
          }
        }
        let p = Math.min(n, m + 1);
        if (nct < n) {
          s[nct] = a.get(nct, nct);
        }
        if (m < p) {
          s[p - 1] = 0;
        }
        if (nrt + 1 < p) {
          e[nrt] = a.get(nrt, p - 1);
        }
        e[p - 1] = 0;
        if (wantu) {
          for (let j = nct; j < nu; j++) {
            for (let i = 0; i < m; i++) {
              U.set(i, j, 0);
            }
            U.set(j, j, 1);
          }
          for (let k = nct - 1; k >= 0; k--) {
            if (s[k] !== 0) {
              for (let j = k + 1; j < nu; j++) {
                let t = 0;
                for (let i = k; i < m; i++) {
                  t += U.get(i, k) * U.get(i, j);
                }
                t = -t / U.get(k, k);
                for (let i = k; i < m; i++) {
                  U.set(i, j, U.get(i, j) + t * U.get(i, k));
                }
              }
              for (let i = k; i < m; i++) {
                U.set(i, k, -U.get(i, k));
              }
              U.set(k, k, 1 + U.get(k, k));
              for (let i = 0; i < k - 1; i++) {
                U.set(i, k, 0);
              }
            } else {
              for (let i = 0; i < m; i++) {
                U.set(i, k, 0);
              }
              U.set(k, k, 1);
            }
          }
        }
        if (wantv) {
          for (let k = n - 1; k >= 0; k--) {
            if (k < nrt && e[k] !== 0) {
              for (let j = k + 1; j < n; j++) {
                let t = 0;
                for (let i = k + 1; i < n; i++) {
                  t += V.get(i, k) * V.get(i, j);
                }
                t = -t / V.get(k + 1, k);
                for (let i = k + 1; i < n; i++) {
                  V.set(i, j, V.get(i, j) + t * V.get(i, k));
                }
              }
            }
            for (let i = 0; i < n; i++) {
              V.set(i, k, 0);
            }
            V.set(k, k, 1);
          }
        }
        let pp = p - 1;
        let eps = Number.EPSILON;
        while (p > 0) {
          let k, kase;
          for (k = p - 2; k >= -1; k--) {
            if (k === -1) {
              break;
            }
            const alpha = Number.MIN_VALUE + eps * Math.abs(s[k] + Math.abs(s[k + 1]));
            if (Math.abs(e[k]) <= alpha || Number.isNaN(e[k])) {
              e[k] = 0;
              break;
            }
          }
          if (k === p - 2) {
            kase = 4;
          } else {
            let ks;
            for (ks = p - 1; ks >= k; ks--) {
              if (ks === k) {
                break;
              }
              let t = (ks !== p ? Math.abs(e[ks]) : 0) + (ks !== k + 1 ? Math.abs(e[ks - 1]) : 0);
              if (Math.abs(s[ks]) <= eps * t) {
                s[ks] = 0;
                break;
              }
            }
            if (ks === k) {
              kase = 3;
            } else if (ks === p - 1) {
              kase = 1;
            } else {
              kase = 2;
              k = ks;
            }
          }
          k++;
          switch (kase) {
            case 1:
              {
                let f = e[p - 2];
                e[p - 2] = 0;
                for (let j = p - 2; j >= k; j--) {
                  let t = hypotenuse(s[j], f);
                  let cs = s[j] / t;
                  let sn = f / t;
                  s[j] = t;
                  if (j !== k) {
                    f = -sn * e[j - 1];
                    e[j - 1] = cs * e[j - 1];
                  }
                  if (wantv) {
                    for (let i = 0; i < n; i++) {
                      t = cs * V.get(i, j) + sn * V.get(i, p - 1);
                      V.set(i, p - 1, -sn * V.get(i, j) + cs * V.get(i, p - 1));
                      V.set(i, j, t);
                    }
                  }
                }
                break;
              }
            case 2:
              {
                let f = e[k - 1];
                e[k - 1] = 0;
                for (let j = k; j < p; j++) {
                  let t = hypotenuse(s[j], f);
                  let cs = s[j] / t;
                  let sn = f / t;
                  s[j] = t;
                  f = -sn * e[j];
                  e[j] = cs * e[j];
                  if (wantu) {
                    for (let i = 0; i < m; i++) {
                      t = cs * U.get(i, j) + sn * U.get(i, k - 1);
                      U.set(i, k - 1, -sn * U.get(i, j) + cs * U.get(i, k - 1));
                      U.set(i, j, t);
                    }
                  }
                }
                break;
              }
            case 3:
              {
                const scale = Math.max(Math.abs(s[p - 1]), Math.abs(s[p - 2]), Math.abs(e[p - 2]), Math.abs(s[k]), Math.abs(e[k]));
                const sp = s[p - 1] / scale;
                const spm1 = s[p - 2] / scale;
                const epm1 = e[p - 2] / scale;
                const sk = s[k] / scale;
                const ek = e[k] / scale;
                const b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2;
                const c = sp * epm1 * (sp * epm1);
                let shift = 0;
                if (b !== 0 || c !== 0) {
                  if (b < 0) {
                    shift = 0 - Math.sqrt(b * b + c);
                  } else {
                    shift = Math.sqrt(b * b + c);
                  }
                  shift = c / (b + shift);
                }
                let f = (sk + sp) * (sk - sp) + shift;
                let g = sk * ek;
                for (let j = k; j < p - 1; j++) {
                  let t = hypotenuse(f, g);
                  if (t === 0) t = Number.MIN_VALUE;
                  let cs = f / t;
                  let sn = g / t;
                  if (j !== k) {
                    e[j - 1] = t;
                  }
                  f = cs * s[j] + sn * e[j];
                  e[j] = cs * e[j] - sn * s[j];
                  g = sn * s[j + 1];
                  s[j + 1] = cs * s[j + 1];
                  if (wantv) {
                    for (let i = 0; i < n; i++) {
                      t = cs * V.get(i, j) + sn * V.get(i, j + 1);
                      V.set(i, j + 1, -sn * V.get(i, j) + cs * V.get(i, j + 1));
                      V.set(i, j, t);
                    }
                  }
                  t = hypotenuse(f, g);
                  if (t === 0) t = Number.MIN_VALUE;
                  cs = f / t;
                  sn = g / t;
                  s[j] = t;
                  f = cs * e[j] + sn * s[j + 1];
                  s[j + 1] = -sn * e[j] + cs * s[j + 1];
                  g = sn * e[j + 1];
                  e[j + 1] = cs * e[j + 1];
                  if (wantu && j < m - 1) {
                    for (let i = 0; i < m; i++) {
                      t = cs * U.get(i, j) + sn * U.get(i, j + 1);
                      U.set(i, j + 1, -sn * U.get(i, j) + cs * U.get(i, j + 1));
                      U.set(i, j, t);
                    }
                  }
                }
                e[p - 2] = f;
                break;
              }
            case 4:
              {
                if (s[k] <= 0) {
                  s[k] = s[k] < 0 ? -s[k] : 0;
                  if (wantv) {
                    for (let i = 0; i <= pp; i++) {
                      V.set(i, k, -V.get(i, k));
                    }
                  }
                }
                while (k < pp) {
                  if (s[k] >= s[k + 1]) {
                    break;
                  }
                  let t = s[k];
                  s[k] = s[k + 1];
                  s[k + 1] = t;
                  if (wantv && k < n - 1) {
                    for (let i = 0; i < n; i++) {
                      t = V.get(i, k + 1);
                      V.set(i, k + 1, V.get(i, k));
                      V.set(i, k, t);
                    }
                  }
                  if (wantu && k < m - 1) {
                    for (let i = 0; i < m; i++) {
                      t = U.get(i, k + 1);
                      U.set(i, k + 1, U.get(i, k));
                      U.set(i, k, t);
                    }
                  }
                  k++;
                }
                p--;
                break;
              }
            // no default
          }
        }
        if (swapped) {
          let tmp = V;
          V = U;
          U = tmp;
        }
        this.m = m;
        this.n = n;
        this.s = s;
        this.U = U;
        this.V = V;
      }
      solve(value) {
        let Y = value;
        let e = this.threshold;
        let scols = this.s.length;
        let Ls = Matrix$1.zeros(scols, scols);
        for (let i = 0; i < scols; i++) {
          if (Math.abs(this.s[i]) <= e) {
            Ls.set(i, i, 0);
          } else {
            Ls.set(i, i, 1 / this.s[i]);
          }
        }
        let U = this.U;
        let V = this.rightSingularVectors;
        let VL = V.mmul(Ls);
        let vrows = V.rows;
        let urows = U.rows;
        let VLU = Matrix$1.zeros(vrows, urows);
        for (let i = 0; i < vrows; i++) {
          for (let j = 0; j < urows; j++) {
            let sum = 0;
            for (let k = 0; k < scols; k++) {
              sum += VL.get(i, k) * U.get(j, k);
            }
            VLU.set(i, j, sum);
          }
        }
        return VLU.mmul(Y);
      }
      solveForDiagonal(value) {
        return this.solve(Matrix$1.diag(value));
      }
      inverse() {
        let V = this.V;
        let e = this.threshold;
        let vrows = V.rows;
        let vcols = V.columns;
        let X = new Matrix$1(vrows, this.s.length);
        for (let i = 0; i < vrows; i++) {
          for (let j = 0; j < vcols; j++) {
            if (Math.abs(this.s[j]) > e) {
              X.set(i, j, V.get(i, j) / this.s[j]);
            }
          }
        }
        let U = this.U;
        let urows = U.rows;
        let ucols = U.columns;
        let Y = new Matrix$1(vrows, urows);
        for (let i = 0; i < vrows; i++) {
          for (let j = 0; j < urows; j++) {
            let sum = 0;
            for (let k = 0; k < ucols; k++) {
              sum += X.get(i, k) * U.get(j, k);
            }
            Y.set(i, j, sum);
          }
        }
        return Y;
      }
      get condition() {
        return this.s[0] / this.s[Math.min(this.m, this.n) - 1];
      }
      get norm2() {
        return this.s[0];
      }
      get rank() {
        let tol = Math.max(this.m, this.n) * this.s[0] * Number.EPSILON;
        let r = 0;
        let s = this.s;
        for (let i = 0, ii = s.length; i < ii; i++) {
          if (s[i] > tol) {
            r++;
          }
        }
        return r;
      }
      get diagonal() {
        return Array.from(this.s);
      }
      get threshold() {
        return Number.EPSILON / 2 * Math.max(this.m, this.n) * this.s[0];
      }
      get leftSingularVectors() {
        return this.U;
      }
      get rightSingularVectors() {
        return this.V;
      }
      get diagonalMatrix() {
        return Matrix$1.diag(this.s);
      }
    }
    function inverse(matrix, useSVD = false) {
      matrix = WrapperMatrix2D.checkMatrix(matrix);
      if (useSVD) {
        return new SingularValueDecomposition(matrix).inverse();
      } else {
        return solve$1(matrix, Matrix$1.eye(matrix.rows));
      }
    }
    function solve$1(leftHandSide, rightHandSide, useSVD = false) {
      leftHandSide = WrapperMatrix2D.checkMatrix(leftHandSide);
      rightHandSide = WrapperMatrix2D.checkMatrix(rightHandSide);
      if (useSVD) {
        return new SingularValueDecomposition(leftHandSide).solve(rightHandSide);
      } else {
        return leftHandSide.isSquare() ? new LuDecomposition(leftHandSide).solve(rightHandSide) : new QrDecomposition(leftHandSide).solve(rightHandSide);
      }
    }
    function determinant(matrix) {
      matrix = Matrix$1.checkMatrix(matrix);
      if (matrix.isSquare()) {
        if (matrix.columns === 0) {
          return 1;
        }
        let a, b, c, d;
        if (matrix.columns === 2) {
          // 2 x 2 matrix
          a = matrix.get(0, 0);
          b = matrix.get(0, 1);
          c = matrix.get(1, 0);
          d = matrix.get(1, 1);
          return a * d - b * c;
        } else if (matrix.columns === 3) {
          // 3 x 3 matrix
          let subMatrix0, subMatrix1, subMatrix2;
          subMatrix0 = new MatrixSelectionView(matrix, [1, 2], [1, 2]);
          subMatrix1 = new MatrixSelectionView(matrix, [1, 2], [0, 2]);
          subMatrix2 = new MatrixSelectionView(matrix, [1, 2], [0, 1]);
          a = matrix.get(0, 0);
          b = matrix.get(0, 1);
          c = matrix.get(0, 2);
          return a * determinant(subMatrix0) - b * determinant(subMatrix1) + c * determinant(subMatrix2);
        } else {
          // general purpose determinant using the LU decomposition
          return new LuDecomposition(matrix).determinant;
        }
      } else {
        throw Error('determinant can only be calculated for a square matrix');
      }
    }
    function xrange(n, exception) {
      let range = [];
      for (let i = 0; i < n; i++) {
        if (i !== exception) {
          range.push(i);
        }
      }
      return range;
    }
    function dependenciesOneRow(error, matrix, index, thresholdValue = 10e-10, thresholdError = 10e-10) {
      if (error > thresholdError) {
        return new Array(matrix.rows + 1).fill(0);
      } else {
        let returnArray = matrix.addRow(index, [0]);
        for (let i = 0; i < returnArray.rows; i++) {
          if (Math.abs(returnArray.get(i, 0)) < thresholdValue) {
            returnArray.set(i, 0, 0);
          }
        }
        return returnArray.to1DArray();
      }
    }
    function linearDependencies(matrix, options = {}) {
      const {
        thresholdValue = 10e-10,
        thresholdError = 10e-10
      } = options;
      matrix = Matrix$1.checkMatrix(matrix);
      let n = matrix.rows;
      let results = new Matrix$1(n, n);
      for (let i = 0; i < n; i++) {
        let b = Matrix$1.columnVector(matrix.getRow(i));
        let Abis = matrix.subMatrixRow(xrange(n, i)).transpose();
        let svd = new SingularValueDecomposition(Abis);
        let x = svd.solve(b);
        let error = Matrix$1.sub(b, Abis.mmul(x)).abs().max();
        results.setRow(i, dependenciesOneRow(error, x, i, thresholdValue, thresholdError));
      }
      return results;
    }
    function pseudoInverse(matrix, threshold = Number.EPSILON) {
      matrix = Matrix$1.checkMatrix(matrix);
      if (matrix.isEmpty()) {
        // with a zero dimension, the pseudo-inverse is the transpose, since all 0xn and nx0 matrices are singular
        // (0xn)*(nx0)*(0xn) = 0xn
        // (nx0)*(0xn)*(nx0) = nx0
        return matrix.transpose();
      }
      let svdSolution = new SingularValueDecomposition(matrix, {
        autoTranspose: true
      });
      let U = svdSolution.leftSingularVectors;
      let V = svdSolution.rightSingularVectors;
      let s = svdSolution.diagonal;
      for (let i = 0; i < s.length; i++) {
        if (Math.abs(s[i]) > threshold) {
          s[i] = 1.0 / s[i];
        } else {
          s[i] = 0.0;
        }
      }
      return V.mmul(Matrix$1.diag(s).mmul(U.transpose()));
    }
    function covariance(xMatrix, yMatrix = xMatrix, options = {}) {
      xMatrix = new Matrix$1(xMatrix);
      let yIsSame = false;
      if (typeof yMatrix === 'object' && !Matrix$1.isMatrix(yMatrix) && !isAnyArray.isAnyArray(yMatrix)) {
        options = yMatrix;
        yMatrix = xMatrix;
        yIsSame = true;
      } else {
        yMatrix = new Matrix$1(yMatrix);
      }
      if (xMatrix.rows !== yMatrix.rows) {
        throw new TypeError('Both matrices must have the same number of rows');
      }
      const {
        center = true
      } = options;
      if (center) {
        xMatrix = xMatrix.center('column');
        if (!yIsSame) {
          yMatrix = yMatrix.center('column');
        }
      }
      const cov = xMatrix.transpose().mmul(yMatrix);
      for (let i = 0; i < cov.rows; i++) {
        for (let j = 0; j < cov.columns; j++) {
          cov.set(i, j, cov.get(i, j) * (1 / (xMatrix.rows - 1)));
        }
      }
      return cov;
    }
    function correlation(xMatrix, yMatrix = xMatrix, options = {}) {
      xMatrix = new Matrix$1(xMatrix);
      let yIsSame = false;
      if (typeof yMatrix === 'object' && !Matrix$1.isMatrix(yMatrix) && !isAnyArray.isAnyArray(yMatrix)) {
        options = yMatrix;
        yMatrix = xMatrix;
        yIsSame = true;
      } else {
        yMatrix = new Matrix$1(yMatrix);
      }
      if (xMatrix.rows !== yMatrix.rows) {
        throw new TypeError('Both matrices must have the same number of rows');
      }
      const {
        center = true,
        scale = true
      } = options;
      if (center) {
        xMatrix.center('column');
        if (!yIsSame) {
          yMatrix.center('column');
        }
      }
      if (scale) {
        xMatrix.scale('column');
        if (!yIsSame) {
          yMatrix.scale('column');
        }
      }
      const sdx = xMatrix.standardDeviation('column', {
        unbiased: true
      });
      const sdy = yIsSame ? sdx : yMatrix.standardDeviation('column', {
        unbiased: true
      });
      const corr = xMatrix.transpose().mmul(yMatrix);
      for (let i = 0; i < corr.rows; i++) {
        for (let j = 0; j < corr.columns; j++) {
          corr.set(i, j, corr.get(i, j) * (1 / (sdx[i] * sdy[j])) * (1 / (xMatrix.rows - 1)));
        }
      }
      return corr;
    }
    class EigenvalueDecomposition {
      constructor(matrix, options = {}) {
        const {
          assumeSymmetric = false
        } = options;
        matrix = WrapperMatrix2D.checkMatrix(matrix);
        if (!matrix.isSquare()) {
          throw new Error('Matrix is not a square matrix');
        }
        if (matrix.isEmpty()) {
          throw new Error('Matrix must be non-empty');
        }
        let n = matrix.columns;
        let V = new Matrix$1(n, n);
        let d = new Float64Array(n);
        let e = new Float64Array(n);
        let value = matrix;
        let i, j;
        let isSymmetric = false;
        if (assumeSymmetric) {
          isSymmetric = true;
        } else {
          isSymmetric = matrix.isSymmetric();
        }
        if (isSymmetric) {
          for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++) {
              V.set(i, j, value.get(i, j));
            }
          }
          tred2(n, e, d, V);
          tql2(n, e, d, V);
        } else {
          let H = new Matrix$1(n, n);
          let ort = new Float64Array(n);
          for (j = 0; j < n; j++) {
            for (i = 0; i < n; i++) {
              H.set(i, j, value.get(i, j));
            }
          }
          orthes(n, H, ort, V);
          hqr2(n, e, d, V, H);
        }
        this.n = n;
        this.e = e;
        this.d = d;
        this.V = V;
      }
      get realEigenvalues() {
        return Array.from(this.d);
      }
      get imaginaryEigenvalues() {
        return Array.from(this.e);
      }
      get eigenvectorMatrix() {
        return this.V;
      }
      get diagonalMatrix() {
        let n = this.n;
        let e = this.e;
        let d = this.d;
        let X = new Matrix$1(n, n);
        let i, j;
        for (i = 0; i < n; i++) {
          for (j = 0; j < n; j++) {
            X.set(i, j, 0);
          }
          X.set(i, i, d[i]);
          if (e[i] > 0) {
            X.set(i, i + 1, e[i]);
          } else if (e[i] < 0) {
            X.set(i, i - 1, e[i]);
          }
        }
        return X;
      }
    }
    function tred2(n, e, d, V) {
      let f, g, h, i, j, k, hh, scale;
      for (j = 0; j < n; j++) {
        d[j] = V.get(n - 1, j);
      }
      for (i = n - 1; i > 0; i--) {
        scale = 0;
        h = 0;
        for (k = 0; k < i; k++) {
          scale = scale + Math.abs(d[k]);
        }
        if (scale === 0) {
          e[i] = d[i - 1];
          for (j = 0; j < i; j++) {
            d[j] = V.get(i - 1, j);
            V.set(i, j, 0);
            V.set(j, i, 0);
          }
        } else {
          for (k = 0; k < i; k++) {
            d[k] /= scale;
            h += d[k] * d[k];
          }
          f = d[i - 1];
          g = Math.sqrt(h);
          if (f > 0) {
            g = -g;
          }
          e[i] = scale * g;
          h = h - f * g;
          d[i - 1] = f - g;
          for (j = 0; j < i; j++) {
            e[j] = 0;
          }
          for (j = 0; j < i; j++) {
            f = d[j];
            V.set(j, i, f);
            g = e[j] + V.get(j, j) * f;
            for (k = j + 1; k <= i - 1; k++) {
              g += V.get(k, j) * d[k];
              e[k] += V.get(k, j) * f;
            }
            e[j] = g;
          }
          f = 0;
          for (j = 0; j < i; j++) {
            e[j] /= h;
            f += e[j] * d[j];
          }
          hh = f / (h + h);
          for (j = 0; j < i; j++) {
            e[j] -= hh * d[j];
          }
          for (j = 0; j < i; j++) {
            f = d[j];
            g = e[j];
            for (k = j; k <= i - 1; k++) {
              V.set(k, j, V.get(k, j) - (f * e[k] + g * d[k]));
            }
            d[j] = V.get(i - 1, j);
            V.set(i, j, 0);
          }
        }
        d[i] = h;
      }
      for (i = 0; i < n - 1; i++) {
        V.set(n - 1, i, V.get(i, i));
        V.set(i, i, 1);
        h = d[i + 1];
        if (h !== 0) {
          for (k = 0; k <= i; k++) {
            d[k] = V.get(k, i + 1) / h;
          }
          for (j = 0; j <= i; j++) {
            g = 0;
            for (k = 0; k <= i; k++) {
              g += V.get(k, i + 1) * V.get(k, j);
            }
            for (k = 0; k <= i; k++) {
              V.set(k, j, V.get(k, j) - g * d[k]);
            }
          }
        }
        for (k = 0; k <= i; k++) {
          V.set(k, i + 1, 0);
        }
      }
      for (j = 0; j < n; j++) {
        d[j] = V.get(n - 1, j);
        V.set(n - 1, j, 0);
      }
      V.set(n - 1, n - 1, 1);
      e[0] = 0;
    }
    function tql2(n, e, d, V) {
      let g, h, i, j, k, l, m, p, r, dl1, c, c2, c3, el1, s, s2;
      for (i = 1; i < n; i++) {
        e[i - 1] = e[i];
      }
      e[n - 1] = 0;
      let f = 0;
      let tst1 = 0;
      let eps = Number.EPSILON;
      for (l = 0; l < n; l++) {
        tst1 = Math.max(tst1, Math.abs(d[l]) + Math.abs(e[l]));
        m = l;
        while (m < n) {
          if (Math.abs(e[m]) <= eps * tst1) {
            break;
          }
          m++;
        }
        if (m > l) {
          do {
            g = d[l];
            p = (d[l + 1] - g) / (2 * e[l]);
            r = hypotenuse(p, 1);
            if (p < 0) {
              r = -r;
            }
            d[l] = e[l] / (p + r);
            d[l + 1] = e[l] * (p + r);
            dl1 = d[l + 1];
            h = g - d[l];
            for (i = l + 2; i < n; i++) {
              d[i] -= h;
            }
            f = f + h;
            p = d[m];
            c = 1;
            c2 = c;
            c3 = c;
            el1 = e[l + 1];
            s = 0;
            s2 = 0;
            for (i = m - 1; i >= l; i--) {
              c3 = c2;
              c2 = c;
              s2 = s;
              g = c * e[i];
              h = c * p;
              r = hypotenuse(p, e[i]);
              e[i + 1] = s * r;
              s = e[i] / r;
              c = p / r;
              p = c * d[i] - s * g;
              d[i + 1] = h + s * (c * g + s * d[i]);
              for (k = 0; k < n; k++) {
                h = V.get(k, i + 1);
                V.set(k, i + 1, s * V.get(k, i) + c * h);
                V.set(k, i, c * V.get(k, i) - s * h);
              }
            }
            p = -s * s2 * c3 * el1 * e[l] / dl1;
            e[l] = s * p;
            d[l] = c * p;
          } while (Math.abs(e[l]) > eps * tst1);
        }
        d[l] = d[l] + f;
        e[l] = 0;
      }
      for (i = 0; i < n - 1; i++) {
        k = i;
        p = d[i];
        for (j = i + 1; j < n; j++) {
          if (d[j] < p) {
            k = j;
            p = d[j];
          }
        }
        if (k !== i) {
          d[k] = d[i];
          d[i] = p;
          for (j = 0; j < n; j++) {
            p = V.get(j, i);
            V.set(j, i, V.get(j, k));
            V.set(j, k, p);
          }
        }
      }
    }
    function orthes(n, H, ort, V) {
      let low = 0;
      let high = n - 1;
      let f, g, h, i, j, m;
      let scale;
      for (m = low + 1; m <= high - 1; m++) {
        scale = 0;
        for (i = m; i <= high; i++) {
          scale = scale + Math.abs(H.get(i, m - 1));
        }
        if (scale !== 0) {
          h = 0;
          for (i = high; i >= m; i--) {
            ort[i] = H.get(i, m - 1) / scale;
            h += ort[i] * ort[i];
          }
          g = Math.sqrt(h);
          if (ort[m] > 0) {
            g = -g;
          }
          h = h - ort[m] * g;
          ort[m] = ort[m] - g;
          for (j = m; j < n; j++) {
            f = 0;
            for (i = high; i >= m; i--) {
              f += ort[i] * H.get(i, j);
            }
            f = f / h;
            for (i = m; i <= high; i++) {
              H.set(i, j, H.get(i, j) - f * ort[i]);
            }
          }
          for (i = 0; i <= high; i++) {
            f = 0;
            for (j = high; j >= m; j--) {
              f += ort[j] * H.get(i, j);
            }
            f = f / h;
            for (j = m; j <= high; j++) {
              H.set(i, j, H.get(i, j) - f * ort[j]);
            }
          }
          ort[m] = scale * ort[m];
          H.set(m, m - 1, scale * g);
        }
      }
      for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
          V.set(i, j, i === j ? 1 : 0);
        }
      }
      for (m = high - 1; m >= low + 1; m--) {
        if (H.get(m, m - 1) !== 0) {
          for (i = m + 1; i <= high; i++) {
            ort[i] = H.get(i, m - 1);
          }
          for (j = m; j <= high; j++) {
            g = 0;
            for (i = m; i <= high; i++) {
              g += ort[i] * V.get(i, j);
            }
            g = g / ort[m] / H.get(m, m - 1);
            for (i = m; i <= high; i++) {
              V.set(i, j, V.get(i, j) + g * ort[i]);
            }
          }
        }
      }
    }
    function hqr2(nn, e, d, V, H) {
      let n = nn - 1;
      let low = 0;
      let high = nn - 1;
      let eps = Number.EPSILON;
      let exshift = 0;
      let norm = 0;
      let p = 0;
      let q = 0;
      let r = 0;
      let s = 0;
      let z = 0;
      let iter = 0;
      let i, j, k, l, m, t, w, x, y;
      let ra, sa, vr, vi;
      let notlast, cdivres;
      for (i = 0; i < nn; i++) {
        if (i < low || i > high) {
          d[i] = H.get(i, i);
          e[i] = 0;
        }
        for (j = Math.max(i - 1, 0); j < nn; j++) {
          norm = norm + Math.abs(H.get(i, j));
        }
      }
      while (n >= low) {
        l = n;
        while (l > low) {
          s = Math.abs(H.get(l - 1, l - 1)) + Math.abs(H.get(l, l));
          if (s === 0) {
            s = norm;
          }
          if (Math.abs(H.get(l, l - 1)) < eps * s) {
            break;
          }
          l--;
        }
        if (l === n) {
          H.set(n, n, H.get(n, n) + exshift);
          d[n] = H.get(n, n);
          e[n] = 0;
          n--;
          iter = 0;
        } else if (l === n - 1) {
          w = H.get(n, n - 1) * H.get(n - 1, n);
          p = (H.get(n - 1, n - 1) - H.get(n, n)) / 2;
          q = p * p + w;
          z = Math.sqrt(Math.abs(q));
          H.set(n, n, H.get(n, n) + exshift);
          H.set(n - 1, n - 1, H.get(n - 1, n - 1) + exshift);
          x = H.get(n, n);
          if (q >= 0) {
            z = p >= 0 ? p + z : p - z;
            d[n - 1] = x + z;
            d[n] = d[n - 1];
            if (z !== 0) {
              d[n] = x - w / z;
            }
            e[n - 1] = 0;
            e[n] = 0;
            x = H.get(n, n - 1);
            s = Math.abs(x) + Math.abs(z);
            p = x / s;
            q = z / s;
            r = Math.sqrt(p * p + q * q);
            p = p / r;
            q = q / r;
            for (j = n - 1; j < nn; j++) {
              z = H.get(n - 1, j);
              H.set(n - 1, j, q * z + p * H.get(n, j));
              H.set(n, j, q * H.get(n, j) - p * z);
            }
            for (i = 0; i <= n; i++) {
              z = H.get(i, n - 1);
              H.set(i, n - 1, q * z + p * H.get(i, n));
              H.set(i, n, q * H.get(i, n) - p * z);
            }
            for (i = low; i <= high; i++) {
              z = V.get(i, n - 1);
              V.set(i, n - 1, q * z + p * V.get(i, n));
              V.set(i, n, q * V.get(i, n) - p * z);
            }
          } else {
            d[n - 1] = x + p;
            d[n] = x + p;
            e[n - 1] = z;
            e[n] = -z;
          }
          n = n - 2;
          iter = 0;
        } else {
          x = H.get(n, n);
          y = 0;
          w = 0;
          if (l < n) {
            y = H.get(n - 1, n - 1);
            w = H.get(n, n - 1) * H.get(n - 1, n);
          }
          if (iter === 10) {
            exshift += x;
            for (i = low; i <= n; i++) {
              H.set(i, i, H.get(i, i) - x);
            }
            s = Math.abs(H.get(n, n - 1)) + Math.abs(H.get(n - 1, n - 2));
            // eslint-disable-next-line no-multi-assign
            x = y = 0.75 * s;
            w = -0.4375 * s * s;
          }
          if (iter === 30) {
            s = (y - x) / 2;
            s = s * s + w;
            if (s > 0) {
              s = Math.sqrt(s);
              if (y < x) {
                s = -s;
              }
              s = x - w / ((y - x) / 2 + s);
              for (i = low; i <= n; i++) {
                H.set(i, i, H.get(i, i) - s);
              }
              exshift += s;
              // eslint-disable-next-line no-multi-assign
              x = y = w = 0.964;
            }
          }
          iter = iter + 1;
          m = n - 2;
          while (m >= l) {
            z = H.get(m, m);
            r = x - z;
            s = y - z;
            p = (r * s - w) / H.get(m + 1, m) + H.get(m, m + 1);
            q = H.get(m + 1, m + 1) - z - r - s;
            r = H.get(m + 2, m + 1);
            s = Math.abs(p) + Math.abs(q) + Math.abs(r);
            p = p / s;
            q = q / s;
            r = r / s;
            if (m === l) {
              break;
            }
            if (Math.abs(H.get(m, m - 1)) * (Math.abs(q) + Math.abs(r)) < eps * (Math.abs(p) * (Math.abs(H.get(m - 1, m - 1)) + Math.abs(z) + Math.abs(H.get(m + 1, m + 1))))) {
              break;
            }
            m--;
          }
          for (i = m + 2; i <= n; i++) {
            H.set(i, i - 2, 0);
            if (i > m + 2) {
              H.set(i, i - 3, 0);
            }
          }
          for (k = m; k <= n - 1; k++) {
            notlast = k !== n - 1;
            if (k !== m) {
              p = H.get(k, k - 1);
              q = H.get(k + 1, k - 1);
              r = notlast ? H.get(k + 2, k - 1) : 0;
              x = Math.abs(p) + Math.abs(q) + Math.abs(r);
              if (x !== 0) {
                p = p / x;
                q = q / x;
                r = r / x;
              }
            }
            if (x === 0) {
              break;
            }
            s = Math.sqrt(p * p + q * q + r * r);
            if (p < 0) {
              s = -s;
            }
            if (s !== 0) {
              if (k !== m) {
                H.set(k, k - 1, -s * x);
              } else if (l !== m) {
                H.set(k, k - 1, -H.get(k, k - 1));
              }
              p = p + s;
              x = p / s;
              y = q / s;
              z = r / s;
              q = q / p;
              r = r / p;
              for (j = k; j < nn; j++) {
                p = H.get(k, j) + q * H.get(k + 1, j);
                if (notlast) {
                  p = p + r * H.get(k + 2, j);
                  H.set(k + 2, j, H.get(k + 2, j) - p * z);
                }
                H.set(k, j, H.get(k, j) - p * x);
                H.set(k + 1, j, H.get(k + 1, j) - p * y);
              }
              for (i = 0; i <= Math.min(n, k + 3); i++) {
                p = x * H.get(i, k) + y * H.get(i, k + 1);
                if (notlast) {
                  p = p + z * H.get(i, k + 2);
                  H.set(i, k + 2, H.get(i, k + 2) - p * r);
                }
                H.set(i, k, H.get(i, k) - p);
                H.set(i, k + 1, H.get(i, k + 1) - p * q);
              }
              for (i = low; i <= high; i++) {
                p = x * V.get(i, k) + y * V.get(i, k + 1);
                if (notlast) {
                  p = p + z * V.get(i, k + 2);
                  V.set(i, k + 2, V.get(i, k + 2) - p * r);
                }
                V.set(i, k, V.get(i, k) - p);
                V.set(i, k + 1, V.get(i, k + 1) - p * q);
              }
            }
          }
        }
      }
      if (norm === 0) {
        return;
      }
      for (n = nn - 1; n >= 0; n--) {
        p = d[n];
        q = e[n];
        if (q === 0) {
          l = n;
          H.set(n, n, 1);
          for (i = n - 1; i >= 0; i--) {
            w = H.get(i, i) - p;
            r = 0;
            for (j = l; j <= n; j++) {
              r = r + H.get(i, j) * H.get(j, n);
            }
            if (e[i] < 0) {
              z = w;
              s = r;
            } else {
              l = i;
              if (e[i] === 0) {
                H.set(i, n, w !== 0 ? -r / w : -r / (eps * norm));
              } else {
                x = H.get(i, i + 1);
                y = H.get(i + 1, i);
                q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
                t = (x * s - z * r) / q;
                H.set(i, n, t);
                H.set(i + 1, n, Math.abs(x) > Math.abs(z) ? (-r - w * t) / x : (-s - y * t) / z);
              }
              t = Math.abs(H.get(i, n));
              if (eps * t * t > 1) {
                for (j = i; j <= n; j++) {
                  H.set(j, n, H.get(j, n) / t);
                }
              }
            }
          }
        } else if (q < 0) {
          l = n - 1;
          if (Math.abs(H.get(n, n - 1)) > Math.abs(H.get(n - 1, n))) {
            H.set(n - 1, n - 1, q / H.get(n, n - 1));
            H.set(n - 1, n, -(H.get(n, n) - p) / H.get(n, n - 1));
          } else {
            cdivres = cdiv(0, -H.get(n - 1, n), H.get(n - 1, n - 1) - p, q);
            H.set(n - 1, n - 1, cdivres[0]);
            H.set(n - 1, n, cdivres[1]);
          }
          H.set(n, n - 1, 0);
          H.set(n, n, 1);
          for (i = n - 2; i >= 0; i--) {
            ra = 0;
            sa = 0;
            for (j = l; j <= n; j++) {
              ra = ra + H.get(i, j) * H.get(j, n - 1);
              sa = sa + H.get(i, j) * H.get(j, n);
            }
            w = H.get(i, i) - p;
            if (e[i] < 0) {
              z = w;
              r = ra;
              s = sa;
            } else {
              l = i;
              if (e[i] === 0) {
                cdivres = cdiv(-ra, -sa, w, q);
                H.set(i, n - 1, cdivres[0]);
                H.set(i, n, cdivres[1]);
              } else {
                x = H.get(i, i + 1);
                y = H.get(i + 1, i);
                vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
                vi = (d[i] - p) * 2 * q;
                if (vr === 0 && vi === 0) {
                  vr = eps * norm * (Math.abs(w) + Math.abs(q) + Math.abs(x) + Math.abs(y) + Math.abs(z));
                }
                cdivres = cdiv(x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi);
                H.set(i, n - 1, cdivres[0]);
                H.set(i, n, cdivres[1]);
                if (Math.abs(x) > Math.abs(z) + Math.abs(q)) {
                  H.set(i + 1, n - 1, (-ra - w * H.get(i, n - 1) + q * H.get(i, n)) / x);
                  H.set(i + 1, n, (-sa - w * H.get(i, n) - q * H.get(i, n - 1)) / x);
                } else {
                  cdivres = cdiv(-r - y * H.get(i, n - 1), -s - y * H.get(i, n), z, q);
                  H.set(i + 1, n - 1, cdivres[0]);
                  H.set(i + 1, n, cdivres[1]);
                }
              }
              t = Math.max(Math.abs(H.get(i, n - 1)), Math.abs(H.get(i, n)));
              if (eps * t * t > 1) {
                for (j = i; j <= n; j++) {
                  H.set(j, n - 1, H.get(j, n - 1) / t);
                  H.set(j, n, H.get(j, n) / t);
                }
              }
            }
          }
        }
      }
      for (i = 0; i < nn; i++) {
        if (i < low || i > high) {
          for (j = i; j < nn; j++) {
            V.set(i, j, H.get(i, j));
          }
        }
      }
      for (j = nn - 1; j >= low; j--) {
        for (i = low; i <= high; i++) {
          z = 0;
          for (k = low; k <= Math.min(j, high); k++) {
            z = z + V.get(i, k) * H.get(k, j);
          }
          V.set(i, j, z);
        }
      }
    }
    function cdiv(xr, xi, yr, yi) {
      let r, d;
      if (Math.abs(yr) > Math.abs(yi)) {
        r = yi / yr;
        d = yr + r * yi;
        return [(xr + r * xi) / d, (xi - r * xr) / d];
      } else {
        r = yr / yi;
        d = yi + r * yr;
        return [(r * xr + xi) / d, (r * xi - xr) / d];
      }
    }
    class CholeskyDecomposition {
      constructor(value) {
        value = WrapperMatrix2D.checkMatrix(value);
        if (!value.isSymmetric()) {
          throw new Error('Matrix is not symmetric');
        }
        let a = value;
        let dimension = a.rows;
        let l = new Matrix$1(dimension, dimension);
        let positiveDefinite = true;
        let i, j, k;
        for (j = 0; j < dimension; j++) {
          let d = 0;
          for (k = 0; k < j; k++) {
            let s = 0;
            for (i = 0; i < k; i++) {
              s += l.get(k, i) * l.get(j, i);
            }
            s = (a.get(j, k) - s) / l.get(k, k);
            l.set(j, k, s);
            d = d + s * s;
          }
          d = a.get(j, j) - d;
          positiveDefinite &&= d > 0;
          l.set(j, j, Math.sqrt(Math.max(d, 0)));
          for (k = j + 1; k < dimension; k++) {
            l.set(j, k, 0);
          }
        }
        this.L = l;
        this.positiveDefinite = positiveDefinite;
      }
      isPositiveDefinite() {
        return this.positiveDefinite;
      }
      solve(value) {
        value = WrapperMatrix2D.checkMatrix(value);
        let l = this.L;
        let dimension = l.rows;
        if (value.rows !== dimension) {
          throw new Error('Matrix dimensions do not match');
        }
        if (this.isPositiveDefinite() === false) {
          throw new Error('Matrix is not positive definite');
        }
        let count = value.columns;
        let B = value.clone();
        let i, j, k;
        for (k = 0; k < dimension; k++) {
          for (j = 0; j < count; j++) {
            for (i = 0; i < k; i++) {
              B.set(k, j, B.get(k, j) - B.get(i, j) * l.get(k, i));
            }
            B.set(k, j, B.get(k, j) / l.get(k, k));
          }
        }
        for (k = dimension - 1; k >= 0; k--) {
          for (j = 0; j < count; j++) {
            for (i = k + 1; i < dimension; i++) {
              B.set(k, j, B.get(k, j) - B.get(i, j) * l.get(i, k));
            }
            B.set(k, j, B.get(k, j) / l.get(k, k));
          }
        }
        return B;
      }
      get lowerTriangularMatrix() {
        return this.L;
      }
    }
    class nipals {
      constructor(X, options = {}) {
        X = WrapperMatrix2D.checkMatrix(X);
        let {
          Y
        } = options;
        const {
          scaleScores = false,
          maxIterations = 1000,
          terminationCriteria = 1e-10
        } = options;
        let u;
        if (Y) {
          if (isAnyArray.isAnyArray(Y) && typeof Y[0] === 'number') {
            Y = Matrix$1.columnVector(Y);
          } else {
            Y = WrapperMatrix2D.checkMatrix(Y);
          }
          if (Y.rows !== X.rows) {
            throw new Error('Y should have the same number of rows as X');
          }
          u = Y.getColumnVector(0);
        } else {
          u = X.getColumnVector(0);
        }
        let diff = 1;
        let t, q, w, tOld;
        for (let counter = 0; counter < maxIterations && diff > terminationCriteria; counter++) {
          w = X.transpose().mmul(u).div(u.transpose().mmul(u).get(0, 0));
          w = w.div(w.norm());
          t = X.mmul(w).div(w.transpose().mmul(w).get(0, 0));
          if (counter > 0) {
            diff = t.clone().sub(tOld).pow(2).sum();
          }
          tOld = t.clone();
          if (Y) {
            q = Y.transpose().mmul(t).div(t.transpose().mmul(t).get(0, 0));
            q = q.div(q.norm());
            u = Y.mmul(q).div(q.transpose().mmul(q).get(0, 0));
          } else {
            u = t;
          }
        }
        if (Y) {
          let p = X.transpose().mmul(t).div(t.transpose().mmul(t).get(0, 0));
          p = p.div(p.norm());
          let xResidual = X.clone().sub(t.clone().mmul(p.transpose()));
          let residual = u.transpose().mmul(t).div(t.transpose().mmul(t).get(0, 0));
          let yResidual = Y.clone().sub(t.clone().mulS(residual.get(0, 0)).mmul(q.transpose()));
          this.t = t;
          this.p = p.transpose();
          this.w = w.transpose();
          this.q = q;
          this.u = u;
          this.s = t.transpose().mmul(t);
          this.xResidual = xResidual;
          this.yResidual = yResidual;
          this.betas = residual;
        } else {
          this.w = w.transpose();
          this.s = t.transpose().mmul(t).sqrt();
          if (scaleScores) {
            this.t = t.clone().div(this.s.get(0, 0));
          } else {
            this.t = t;
          }
          this.xResidual = X.sub(t.mmul(w.transpose()));
        }
      }
    }
    matrix.AbstractMatrix = AbstractMatrix;
    matrix.CHO = CholeskyDecomposition;
    matrix.CholeskyDecomposition = CholeskyDecomposition;
    matrix.DistanceMatrix = DistanceMatrix;
    matrix.EVD = EigenvalueDecomposition;
    matrix.EigenvalueDecomposition = EigenvalueDecomposition;
    matrix.LU = LuDecomposition;
    matrix.LuDecomposition = LuDecomposition;
    var Matrix_1 = matrix.Matrix = Matrix$1;
    matrix.MatrixColumnSelectionView = MatrixColumnSelectionView;
    matrix.MatrixColumnView = MatrixColumnView;
    matrix.MatrixFlipColumnView = MatrixFlipColumnView;
    matrix.MatrixFlipRowView = MatrixFlipRowView;
    matrix.MatrixRowSelectionView = MatrixRowSelectionView;
    matrix.MatrixRowView = MatrixRowView;
    matrix.MatrixSelectionView = MatrixSelectionView;
    matrix.MatrixSubView = MatrixSubView;
    var MatrixTransposeView_1 = matrix.MatrixTransposeView = MatrixTransposeView$1;
    matrix.NIPALS = nipals;
    matrix.Nipals = nipals;
    matrix.QR = QrDecomposition;
    matrix.QrDecomposition = QrDecomposition;
    matrix.SVD = SingularValueDecomposition;
    matrix.SingularValueDecomposition = SingularValueDecomposition;
    matrix.SymmetricMatrix = SymmetricMatrix;
    matrix.WrapperMatrix1D = WrapperMatrix1D;
    matrix.WrapperMatrix2D = WrapperMatrix2D;
    matrix.correlation = correlation;
    matrix.covariance = covariance;
    var _default = matrix.default = Matrix$1;
    matrix.determinant = determinant;
    matrix.inverse = inverse;
    matrix.linearDependencies = linearDependencies;
    matrix.pseudoInverse = pseudoInverse;
    var solve_1 = matrix.solve = solve$1;
    matrix.wrap = wrap;

    const Matrix = Matrix_1;
    const MatrixTransposeView = MatrixTransposeView_1;
    _default.Matrix ? _default.Matrix : Matrix_1;
    const solve = solve_1;

    /**
     * Computes the mean value of an array of values.
     * @param array - array of numbers
     * @param options - options
     */
    function xMean(array, options = {}) {
      xCheck(array);
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex(array, options);
      let sumValue = array[fromIndex];
      for (let i = fromIndex + 1; i <= toIndex; i++) {
        sumValue += array[i];
      }
      return sumValue / (toIndex - fromIndex + 1);
    }

    /**
     * Finds the variance of the data
     * @param values - the values of the array
     * @param options - options
     * @returns variance
     */
    function xVariance(values, options = {}) {
      if (!isAnyArray$1(values)) {
        throw new TypeError('input must be an array');
      }
      const {
        unbiased = true,
        mean = xMean(values)
      } = options;
      let sqrError = 0;
      for (const value of values) {
        const x = value - mean;
        sqrError += x * x;
      }
      if (unbiased) {
        return sqrError / (values.length - 1);
      } else {
        return sqrError / values.length;
      }
    }

    /**
     * Finds the standard deviation for the data at hand
     * @param values - values in the data
     * @param options - options
     * @returns standard deviation
     */
    function xStandardDeviation(values, options = {}) {
      return Math.sqrt(xVariance(values, options));
    }

    /**
     * This function divide the first array by the second array or a constant value to each element of the first array
     * @param array1 - first array
     * @param array2 - second array or number
     * @param options - options
     */
    function xDivide(array1, array2, options = {}) {
      let isConstant = false;
      let constant = 0;
      if (isAnyArray$1(array2)) {
        if (array1.length !== array2.length) {
          throw new RangeError('size of array1 and array2 must be identical');
        }
      } else {
        isConstant = true;
        constant = array2;
      }
      const array3 = getOutputArray(options.output, array1.length);
      if (isConstant) {
        for (let i = 0; i < array1.length; i++) {
          array3[i] = array1[i] / constant;
        }
      } else {
        for (let i = 0; i < array1.length; i++) {
          array3[i] = array1[i] / array2[i];
        }
      }
      return array3;
    }

    /**
     * Returns a copy of the data as a Float64Array.
     * @param array - array of numbers
     */
    function xEnsureFloat64(array) {
      xCheck(array);
      if (array instanceof Float64Array) {
        return array.slice(0);
      }
      return Float64Array.from(array);
    }

    function FFT(size) {
      this.size = size | 0;
      if (this.size <= 1 || (this.size & this.size - 1) !== 0) throw new Error('FFT size must be a power of two and bigger than 1');
      this._csize = size << 1;

      // NOTE: Use of `var` is intentional for old V8 versions
      var table = new Array(this.size * 2);
      for (var i = 0; i < table.length; i += 2) {
        const angle = Math.PI * i / this.size;
        table[i] = Math.cos(angle);
        table[i + 1] = -Math.sin(angle);
      }
      this.table = table;

      // Find size's power of two
      var power = 0;
      for (var t = 1; this.size > t; t <<= 1) power++;

      // Calculate initial step's width:
      //   * If we are full radix-4 - it is 2x smaller to give inital len=8
      //   * Otherwise it is the same as `power` to give len=4
      this._width = power % 2 === 0 ? power - 1 : power;

      // Pre-compute bit-reversal patterns
      this._bitrev = new Array(1 << this._width);
      for (var j = 0; j < this._bitrev.length; j++) {
        this._bitrev[j] = 0;
        for (var shift = 0; shift < this._width; shift += 2) {
          var revShift = this._width - shift - 2;
          this._bitrev[j] |= (j >>> shift & 3) << revShift;
        }
      }
      this._out = null;
      this._data = null;
      this._inv = 0;
    }
    FFT.prototype.fromComplexArray = function fromComplexArray(complex, storage) {
      var res = storage || new Array(complex.length >>> 1);
      for (var i = 0; i < complex.length; i += 2) res[i >>> 1] = complex[i];
      return res;
    };
    FFT.prototype.createComplexArray = function createComplexArray() {
      const res = new Array(this._csize);
      for (var i = 0; i < res.length; i++) res[i] = 0;
      return res;
    };
    FFT.prototype.toComplexArray = function toComplexArray(input, storage) {
      var res = storage || this.createComplexArray();
      for (var i = 0; i < res.length; i += 2) {
        res[i] = input[i >>> 1];
        res[i + 1] = 0;
      }
      return res;
    };
    FFT.prototype.completeSpectrum = function completeSpectrum(spectrum) {
      var size = this._csize;
      var half = size >>> 1;
      for (var i = 2; i < half; i += 2) {
        spectrum[size - i] = spectrum[i];
        spectrum[size - i + 1] = -spectrum[i + 1];
      }
    };
    FFT.prototype.transform = function transform(out, data) {
      if (out === data) throw new Error('Input and output buffers must be different');
      this._out = out;
      this._data = data;
      this._inv = 0;
      this._transform4();
      this._out = null;
      this._data = null;
    };
    FFT.prototype.realTransform = function realTransform(out, data) {
      if (out === data) throw new Error('Input and output buffers must be different');
      this._out = out;
      this._data = data;
      this._inv = 0;
      this._realTransform4();
      this._out = null;
      this._data = null;
    };
    FFT.prototype.inverseTransform = function inverseTransform(out, data) {
      if (out === data) throw new Error('Input and output buffers must be different');
      this._out = out;
      this._data = data;
      this._inv = 1;
      this._transform4();
      for (var i = 0; i < out.length; i++) out[i] /= this.size;
      this._out = null;
      this._data = null;
    };

    // radix-4 implementation
    //
    // NOTE: Uses of `var` are intentional for older V8 version that do not
    // support both `let compound assignments` and `const phi`
    FFT.prototype._transform4 = function _transform4() {
      var out = this._out;
      var size = this._csize;

      // Initial step (permute and transform)
      var width = this._width;
      var step = 1 << width;
      var len = size / step << 1;
      var outOff;
      var t;
      var bitrev = this._bitrev;
      if (len === 4) {
        for (outOff = 0, t = 0; outOff < size; outOff += len, t++) {
          const off = bitrev[t];
          this._singleTransform2(outOff, off, step);
        }
      } else {
        // len === 8
        for (outOff = 0, t = 0; outOff < size; outOff += len, t++) {
          const off = bitrev[t];
          this._singleTransform4(outOff, off, step);
        }
      }

      // Loop through steps in decreasing order
      var inv = this._inv ? -1 : 1;
      var table = this.table;
      for (step >>= 2; step >= 2; step >>= 2) {
        len = size / step << 1;
        var quarterLen = len >>> 2;

        // Loop through offsets in the data
        for (outOff = 0; outOff < size; outOff += len) {
          // Full case
          var limit = outOff + quarterLen;
          for (var i = outOff, k = 0; i < limit; i += 2, k += step) {
            const A = i;
            const B = A + quarterLen;
            const C = B + quarterLen;
            const D = C + quarterLen;

            // Original values
            const Ar = out[A];
            const Ai = out[A + 1];
            const Br = out[B];
            const Bi = out[B + 1];
            const Cr = out[C];
            const Ci = out[C + 1];
            const Dr = out[D];
            const Di = out[D + 1];

            // Middle values
            const MAr = Ar;
            const MAi = Ai;
            const tableBr = table[k];
            const tableBi = inv * table[k + 1];
            const MBr = Br * tableBr - Bi * tableBi;
            const MBi = Br * tableBi + Bi * tableBr;
            const tableCr = table[2 * k];
            const tableCi = inv * table[2 * k + 1];
            const MCr = Cr * tableCr - Ci * tableCi;
            const MCi = Cr * tableCi + Ci * tableCr;
            const tableDr = table[3 * k];
            const tableDi = inv * table[3 * k + 1];
            const MDr = Dr * tableDr - Di * tableDi;
            const MDi = Dr * tableDi + Di * tableDr;

            // Pre-Final values
            const T0r = MAr + MCr;
            const T0i = MAi + MCi;
            const T1r = MAr - MCr;
            const T1i = MAi - MCi;
            const T2r = MBr + MDr;
            const T2i = MBi + MDi;
            const T3r = inv * (MBr - MDr);
            const T3i = inv * (MBi - MDi);

            // Final values
            const FAr = T0r + T2r;
            const FAi = T0i + T2i;
            const FCr = T0r - T2r;
            const FCi = T0i - T2i;
            const FBr = T1r + T3i;
            const FBi = T1i - T3r;
            const FDr = T1r - T3i;
            const FDi = T1i + T3r;
            out[A] = FAr;
            out[A + 1] = FAi;
            out[B] = FBr;
            out[B + 1] = FBi;
            out[C] = FCr;
            out[C + 1] = FCi;
            out[D] = FDr;
            out[D + 1] = FDi;
          }
        }
      }
    };

    // radix-2 implementation
    //
    // NOTE: Only called for len=4
    FFT.prototype._singleTransform2 = function _singleTransform2(outOff, off, step) {
      const out = this._out;
      const data = this._data;
      const evenR = data[off];
      const evenI = data[off + 1];
      const oddR = data[off + step];
      const oddI = data[off + step + 1];
      const leftR = evenR + oddR;
      const leftI = evenI + oddI;
      const rightR = evenR - oddR;
      const rightI = evenI - oddI;
      out[outOff] = leftR;
      out[outOff + 1] = leftI;
      out[outOff + 2] = rightR;
      out[outOff + 3] = rightI;
    };

    // radix-4
    //
    // NOTE: Only called for len=8
    FFT.prototype._singleTransform4 = function _singleTransform4(outOff, off, step) {
      const out = this._out;
      const data = this._data;
      const inv = this._inv ? -1 : 1;
      const step2 = step * 2;
      const step3 = step * 3;

      // Original values
      const Ar = data[off];
      const Ai = data[off + 1];
      const Br = data[off + step];
      const Bi = data[off + step + 1];
      const Cr = data[off + step2];
      const Ci = data[off + step2 + 1];
      const Dr = data[off + step3];
      const Di = data[off + step3 + 1];

      // Pre-Final values
      const T0r = Ar + Cr;
      const T0i = Ai + Ci;
      const T1r = Ar - Cr;
      const T1i = Ai - Ci;
      const T2r = Br + Dr;
      const T2i = Bi + Di;
      const T3r = inv * (Br - Dr);
      const T3i = inv * (Bi - Di);

      // Final values
      const FAr = T0r + T2r;
      const FAi = T0i + T2i;
      const FBr = T1r + T3i;
      const FBi = T1i - T3r;
      const FCr = T0r - T2r;
      const FCi = T0i - T2i;
      const FDr = T1r - T3i;
      const FDi = T1i + T3r;
      out[outOff] = FAr;
      out[outOff + 1] = FAi;
      out[outOff + 2] = FBr;
      out[outOff + 3] = FBi;
      out[outOff + 4] = FCr;
      out[outOff + 5] = FCi;
      out[outOff + 6] = FDr;
      out[outOff + 7] = FDi;
    };

    // Real input radix-4 implementation
    FFT.prototype._realTransform4 = function _realTransform4() {
      var out = this._out;
      var size = this._csize;

      // Initial step (permute and transform)
      var width = this._width;
      var step = 1 << width;
      var len = size / step << 1;
      var outOff;
      var t;
      var bitrev = this._bitrev;
      if (len === 4) {
        for (outOff = 0, t = 0; outOff < size; outOff += len, t++) {
          const off = bitrev[t];
          this._singleRealTransform2(outOff, off >>> 1, step >>> 1);
        }
      } else {
        // len === 8
        for (outOff = 0, t = 0; outOff < size; outOff += len, t++) {
          const off = bitrev[t];
          this._singleRealTransform4(outOff, off >>> 1, step >>> 1);
        }
      }

      // Loop through steps in decreasing order
      var inv = this._inv ? -1 : 1;
      var table = this.table;
      for (step >>= 2; step >= 2; step >>= 2) {
        len = size / step << 1;
        var halfLen = len >>> 1;
        var quarterLen = halfLen >>> 1;
        var hquarterLen = quarterLen >>> 1;

        // Loop through offsets in the data
        for (outOff = 0; outOff < size; outOff += len) {
          for (var i = 0, k = 0; i <= hquarterLen; i += 2, k += step) {
            var A = outOff + i;
            var B = A + quarterLen;
            var C = B + quarterLen;
            var D = C + quarterLen;

            // Original values
            var Ar = out[A];
            var Ai = out[A + 1];
            var Br = out[B];
            var Bi = out[B + 1];
            var Cr = out[C];
            var Ci = out[C + 1];
            var Dr = out[D];
            var Di = out[D + 1];

            // Middle values
            var MAr = Ar;
            var MAi = Ai;
            var tableBr = table[k];
            var tableBi = inv * table[k + 1];
            var MBr = Br * tableBr - Bi * tableBi;
            var MBi = Br * tableBi + Bi * tableBr;
            var tableCr = table[2 * k];
            var tableCi = inv * table[2 * k + 1];
            var MCr = Cr * tableCr - Ci * tableCi;
            var MCi = Cr * tableCi + Ci * tableCr;
            var tableDr = table[3 * k];
            var tableDi = inv * table[3 * k + 1];
            var MDr = Dr * tableDr - Di * tableDi;
            var MDi = Dr * tableDi + Di * tableDr;

            // Pre-Final values
            var T0r = MAr + MCr;
            var T0i = MAi + MCi;
            var T1r = MAr - MCr;
            var T1i = MAi - MCi;
            var T2r = MBr + MDr;
            var T2i = MBi + MDi;
            var T3r = inv * (MBr - MDr);
            var T3i = inv * (MBi - MDi);

            // Final values
            var FAr = T0r + T2r;
            var FAi = T0i + T2i;
            var FBr = T1r + T3i;
            var FBi = T1i - T3r;
            out[A] = FAr;
            out[A + 1] = FAi;
            out[B] = FBr;
            out[B + 1] = FBi;

            // Output final middle point
            if (i === 0) {
              var FCr = T0r - T2r;
              var FCi = T0i - T2i;
              out[C] = FCr;
              out[C + 1] = FCi;
              continue;
            }

            // Do not overwrite ourselves
            if (i === hquarterLen) continue;

            // In the flipped case:
            // MAi = -MAi
            // MBr=-MBi, MBi=-MBr
            // MCr=-MCr
            // MDr=MDi, MDi=MDr
            var ST0r = T1r;
            var ST0i = -T1i;
            var ST1r = T0r;
            var ST1i = -T0i;
            var ST2r = -inv * T3i;
            var ST2i = -inv * T3r;
            var ST3r = -inv * T2i;
            var ST3i = -inv * T2r;
            var SFAr = ST0r + ST2r;
            var SFAi = ST0i + ST2i;
            var SFBr = ST1r + ST3i;
            var SFBi = ST1i - ST3r;
            var SA = outOff + quarterLen - i;
            var SB = outOff + halfLen - i;
            out[SA] = SFAr;
            out[SA + 1] = SFAi;
            out[SB] = SFBr;
            out[SB + 1] = SFBi;
          }
        }
      }
    };

    // radix-2 implementation
    //
    // NOTE: Only called for len=4
    FFT.prototype._singleRealTransform2 = function _singleRealTransform2(outOff, off, step) {
      const out = this._out;
      const data = this._data;
      const evenR = data[off];
      const oddR = data[off + step];
      const leftR = evenR + oddR;
      const rightR = evenR - oddR;
      out[outOff] = leftR;
      out[outOff + 1] = 0;
      out[outOff + 2] = rightR;
      out[outOff + 3] = 0;
    };

    // radix-4
    //
    // NOTE: Only called for len=8
    FFT.prototype._singleRealTransform4 = function _singleRealTransform4(outOff, off, step) {
      const out = this._out;
      const data = this._data;
      const inv = this._inv ? -1 : 1;
      const step2 = step * 2;
      const step3 = step * 3;

      // Original values
      const Ar = data[off];
      const Br = data[off + step];
      const Cr = data[off + step2];
      const Dr = data[off + step3];

      // Pre-Final values
      const T0r = Ar + Cr;
      const T1r = Ar - Cr;
      const T2r = Br + Dr;
      const T3r = inv * (Br - Dr);

      // Final values
      const FAr = T0r + T2r;
      const FBr = T1r;
      const FBi = -T3r;
      const FCr = T0r - T2r;
      const FDr = T1r;
      const FDi = T3r;
      out[outOff] = FAr;
      out[outOff + 1] = 0;
      out[outOff + 2] = FBr;
      out[outOff + 3] = FBi;
      out[outOff + 4] = FCr;
      out[outOff + 5] = 0;
      out[outOff + 6] = FDr;
      out[outOff + 7] = FDi;
    };

    /**
     * Create an array with numbers between "from" and "to" of length "length"
     * @param options - options
     * @returns - array of distributed numbers between "from" and "to"
     */
    function createFromToArray(options = {}) {
      const {
        from = 0,
        to = 1,
        length = 1000,
        includeFrom = true,
        includeTo = true,
        distribution = 'uniform'
      } = options;
      const array = new Float64Array(length);
      let div = length;
      if (includeFrom && includeTo) {
        div = length - 1;
      } else if (!includeFrom && includeTo || includeFrom && !includeTo) {
        div = length;
      } else if (!includeFrom && !includeTo) {
        div = length + 1;
      }
      const delta = (to - from) / div;
      if (distribution === 'uniform') {
        if (includeFrom) {
          let index = 0;
          while (index < length) {
            array[index] = from + delta * index;
            index++;
          }
        } else {
          let index = 0;
          while (index < length) {
            array[index] = from + delta * (index + 1);
            index++;
          }
        }
      } else if (distribution === 'log') {
        const base = (to / from) ** (1 / div);
        const firstExponent = Math.log(from) / Math.log(base);
        if (includeFrom) {
          let index = 0;
          while (index < length) {
            array[index] = base ** (firstExponent + index);
            index++;
          }
        } else {
          let index = 0;
          while (index < length) {
            array[index] = base ** (firstExponent + index + 1);
            index++;
          }
        }
      } else {
        throw new Error('distribution must be uniform or log');
      }
      return array;
    }

    /* eslint-disable @typescript-eslint/no-explicit-any */
    /**
     * Stringify an object and convert all typed arrays to arrays
     * @param object
     * @param replacer
     * @param space
     * @returns
     */
    function stringify(object, replacer, space) {
      const internalReplacer = (key, value) => {
        if (ArrayBuffer.isView(value)) {
          value = Array.from(value);
        }
        return value;
      };
      return JSON.stringify(object, internalReplacer, space);
    }

    /**
     * Computes the maximal value of an array of values
     * @param array - array of numbers
     * @param options - options
     */
    function xMaxValue(array, options = {}) {
      xCheck(array);
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex(array, options);
      let maxValue = array[fromIndex];
      for (let i = fromIndex + 1; i <= toIndex; i++) {
        if (array[i] > maxValue) {
          maxValue = array[i];
        }
      }
      return maxValue;
    }

    /**
     * Computes the minimal value of an array of values.
     * @param array - array of numbers
     * @param options - options
     */
    function xMinValue(array, options = {}) {
      xCheck(array);
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex(array, options);
      let minValue = array[fromIndex];
      for (let i = fromIndex + 1; i <= toIndex; i++) {
        if (array[i] < minValue) {
          minValue = array[i];
        }
      }
      return minValue;
    }

    /**
     * Check if the values are separated always by the same difference
     * @param array - Monotone growing array of number
     * @param options
     */
    function xIsEquallySpaced(array, options = {}) {
      if (array.length < 3) return true;
      const {
        tolerance = 0.05
      } = options;
      let maxDx = 0;
      let minDx = Number.MAX_SAFE_INTEGER;
      for (let i = 0; i < array.length - 1; ++i) {
        const absoluteDifference = array[i + 1] - array[i];
        if (absoluteDifference < minDx) {
          minDx = absoluteDifference;
        }
        if (absoluteDifference > maxDx) {
          maxDx = absoluteDifference;
        }
      }
      return (maxDx - minDx) / maxDx < tolerance;
    }

    /**
     * Returns true if x is monotonic.
     * @param array - array of numbers.
     * @returns 1 if monotonic increasing, -1 if monotonic decreasing, 0 if not monotonic.
     */
    function xIsMonotonic(array) {
      if (array.length <= 2) {
        return 1;
      }
      if (array[0] === array[1]) {
        // maybe a constant series
        for (let i = 1; i < array.length - 1; i++) {
          if (array[i] !== array[i + 1]) return 0;
        }
        return 1;
      }
      if (array[0] < array.at(-1)) {
        for (let i = 0; i < array.length - 1; i++) {
          if (array[i] >= array[i + 1]) return 0;
        }
        return 1;
      } else {
        for (let i = 0; i < array.length - 1; i++) {
          if (array[i] <= array[i + 1]) return 0;
        }
        return -1;
      }
    }

    /**
     * This function calculates the median absolute deviation (MAD).
     * https://en.wikipedia.org/wiki/Median_absolute_deviation
     * @param array
     */
    function xMedianAbsoluteDeviation(array) {
      const median = xMedian(array);
      const averageDeviations = new Float64Array(array.length);
      for (let i = 0; i < array.length; i++) {
        averageDeviations[i] = Math.abs(array[i] - median);
      }
      return {
        median,
        mad: xMedian(averageDeviations)
      };
    }

    /**
     * Return min and max values of an array.
     * @param array - array of number
     * @returns - Object with 2 properties, min and max.
     */
    function xMinMaxValues(array) {
      xCheck(array);
      let min = array[0];
      let max = array[0];
      for (const value of array) {
        if (value < min) min = value;
        if (value > max) max = value;
      }
      return {
        min,
        max
      };
    }

    /*
    Adapted from: https://github.com/compute-io/erfcinv/blob/aa116e23883839359e310ad41a7c42f72815fc1e/lib/number.js

    The MIT License (MIT)

    Copyright (c) 2014-2015 The Compute.io Authors. All rights reserved.

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.


    Boost Software License - Version 1.0 - August 17th, 2003

    Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following:

    The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
    /* eslint-disable no-loss-of-precision */
    // Coefficients for erfcinv on [0, 0.5]:
    const Y1 = 8.91314744949340820313e-2;
    const P1 = [-0.005387729650712429, 8.22687874676915743155e-3, 2.19878681111168899165e-2, -0.03656379714117627, -0.012692614766297404, 3.34806625409744615033e-2, -0.008368748197417368, -5087819496582806e-19];
    const Q1 = [8.86216390456424707504e-4, -0.0023339375937419, 7.95283687341571680018e-2, -0.05273963823400997, -0.7122890234154284, 6.62328840472002992063e-1, 1.56221558398423026363, -1.5657455823417585, -0.9700050433032906, 1];
    // Coefficients for erfcinv for 0.5 > 1-x >= 0:
    const Y2 = 2.249481201171875;
    const P2 = [-3.6719225470772936, 2.11294655448340526258e1, 1.7445385985570866523e1, -44.6382324441787, -18.851064805871424, 1.76447298408374015486e1, 8.37050328343119927838, 1.05264680699391713268e-1, -0.20243350835593876];
    const Q2 = [1.72114765761200282724, -22.643693341313973, 1.08268667355460159008e1, 4.85609213108739935468e1, -20.14326346804852, -28.66081804998, 3.9713437953343869095, 6.24264124854247537712, 1];
    // Coefficients for erfcinv for sqrt( -log(1-x)):
    const Y3 = 8.07220458984375e-1;
    const P3 = [-681149956853777e-24, 2.85225331782217055858e-8, -6.794655751811263e-7, 2.14558995388805277169e-3, 2.90157910005329060432e-2, 1.42869534408157156766e-1, 3.37785538912035898924e-1, 3.87079738972604337464e-1, 1.17030156341995252019e-1, -0.16379404719331705, -0.1311027816799519];
    const Q3 = [1.105924229346489121e-2, 1.52264338295331783612e-1, 8.48854343457902036425e-1, 2.59301921623620271374, 4.77846592945843778382, 5.38168345707006855425, 3.46625407242567245975, 1];
    const Y4 = 9.3995571136474609375e-1;
    const P4 = [2.66339227425782031962e-12, -2304047769118826e-25, 4.60469890584317994083e-6, 1.57544617424960554631e-4, 1.87123492819559223345e-3, 9.50804701325919603619e-3, 1.85573306514231072324e-2, -0.0022242652921344794, -0.0350353787183178];
    const Q4 = [7.64675292302794483503e-5, 2.63861676657015992959e-3, 3.41589143670947727934e-2, 2.20091105764131249824e-1, 7.62059164553623404043e-1, 1.3653349817554063097, 1];
    const Y5 = 9.8362827301025390625e-1;
    const P5 = [9.9055709973310326855e-17, -2811287356288318e-29, 4.62596163522878599135e-9, 4.49696789927706453732e-7, 1.49624783758342370182e-5, 2.09386317487588078668e-4, 1.05628862152492910091e-3, -0.0011295143874558028, -0.016743100507663373];
    const Q5 = [2.82243172016108031869e-7, 2.75335474764726041141e-5, 9.64011807005165528527e-4, 1.60746087093676504695e-2, 1.38151865749083321638e-1, 5.91429344886417493481e-1, 1];
    /**
     * Polyval.
     * @param c - Array of Number.
     * @param x - Number.
     * @returns Number.
     */
    function polyval(c, x) {
      let p = 0;
      for (const coef of c) {
        p = p * x + coef;
      }
      return p;
    }
    /**
     * Calculates a rational approximation.
     * @private
     * @param x - Number.
     * @param v - Number.
     * @param P - Array of polynomial coefficients.
     * @param Q - Array of polynomial coefficients.
     * @param Y - Number.
     * @returns Rational approximation.
     */
    function calc(x, v, P, Q, Y) {
      const s = x - v;
      const r = polyval(P, s) / polyval(Q, s);
      return Y * x + r * x;
    }
    /**
     * Evaluates the complementary inverse error function for an input value.
     * @private
     * @param x - Input value.
     * @returns Evaluated complementary inverse error function.
     */
    function erfcinv(x) {
      let sign = false;
      let val;
      let q;
      let g;
      let r;
      // [1] Special cases...
      // NaN:
      if (Number.isNaN(x)) {
        return Number.NaN;
      }
      // x not on the interval: [0,2]
      if (x < 0 || x > 2) {
        throw new RangeError(`erfcinv()::invalid input argument. Value must be on the interval [0,2]. Value: \`${x}\`.`);
      }
      if (x === 0) {
        return Number.POSITIVE_INFINITY;
      }
      if (x === 2) {
        return Number.NEGATIVE_INFINITY;
      }
      if (x === 1) {
        return 0;
      }
      // [2] Get the sign and make use of `erfc` reflection formula: `erfc(-z)=2 - erfc(z)`...
      if (x > 1) {
        q = 2 - x;
        x = 1 - q;
        sign = true;
      } else {
        q = x;
        x = 1 - x;
      }
      // [3] |x| <= 0.5
      if (x <= 0.5) {
        g = x * (x + 10);
        r = polyval(P1, x) / polyval(Q1, x);
        val = g * Y1 + g * r;
        return sign ? -val : val;
      }
      // [4] 1-|x| >= 0.25
      if (q >= 0.25) {
        g = Math.sqrt(-2 * Math.log(q));
        q = q - 0.25;
        r = polyval(P2, q) / polyval(Q2, q);
        val = g / (Y2 + r);
        return sign ? -val : val;
      }
      q = Math.sqrt(-Math.log(q));
      // [5] q < 3
      if (q < 3) {
        return calc(q, 1.125, P3, Q3, Y3);
      }
      // [6] q < 6
      if (q < 6) {
        return calc(q, 3, P4, Q4, Y4);
      }
      // Note that the smallest number in JavaScript is 5e-324. Math.sqrt( -Math.log( 5e-324 ) ) ~27.2844
      return calc(q, 6, P5, Q5, Y5);
      // Note that in the boost library, they are able to go to much smaller values, as 128 bit long doubles support ~1e-5000; something which JavaScript does not natively support.
    }

    /**
     * Applies a simple normalization inverse transformation to the input data.
     * @param data - The input array of numbers to be transformed.
     * @param options - Optional parameters for the transformation.
     * @returns A new Float64Array containing the transformed data.
     */
    function simpleNormInv(data, options = {}) {
      const {
        magnitudeMode = false
      } = options;
      const result = new Float64Array(data.length);
      if (magnitudeMode) {
        for (let i = 0; i < result.length; i++) {
          result[i] = -Math.sqrt(-2 * Math.log(1 - data[i]));
        }
      } else {
        for (let i = 0; i < result.length; i++) {
          result[i] = -1 * Math.SQRT2 * erfcinv(2 * data[i]);
        }
      }
      return result;
    }
    /**
     * Convenience wrapper for single number processing by simpleNormInv function.
     * @param data - The number to be normalized.
     * @param options - The options for the normalization process.
     * @returns The normalized number.
     */
    function simpleNormInvNumber(data, options = {}) {
      return simpleNormInv([data], options)[0];
    }

    /**
     * Determine noise level by san plot methodology (https://doi.org/10.1002/mrc.4882)
     * @param array - real or magnitude spectra data.
     * @param options - options
     * @returns noise level
     */
    function xNoiseSanPlot(array, options = {}) {
      const {
        mask,
        cutOff,
        refine = true,
        magnitudeMode = false,
        scaleFactor = 1,
        factorStd = 5,
        fixOffset = true
      } = options;
      const input = prepareData(array, {
        scaleFactor,
        mask
      });
      if (fixOffset && !magnitudeMode) {
        const medianIndex = Math.floor(input.length / 2);
        const median = input.length % 2 === 0 ? 0.5 * (input[medianIndex - 1] + input[medianIndex]) : input[medianIndex];
        for (let i = 0; i < input.length; i++) {
          input[i] -= median;
        }
      }
      const firstNegativeValueIndex = input.at(-1) >= 0 ? input.length : input.findIndex(e => e < 0);
      let lastPositiveValueIndex = firstNegativeValueIndex - 1;
      for (let i = lastPositiveValueIndex; i >= 0; i--) {
        if (input[i] > 0) {
          lastPositiveValueIndex = i;
          break;
        }
      }
      const signPositive = input.slice(0, lastPositiveValueIndex + 1);
      const signNegative = input.slice(firstNegativeValueIndex);
      const cutOffDist = cutOff || determineCutOff(signPositive, {
        magnitudeMode
      });
      const pIndex = Math.floor(signPositive.length * cutOffDist);
      const initialNoiseLevelPositive = signPositive[pIndex];
      const skyPoint = signPositive[0];
      let initialNoiseLevelNegative;
      if (signNegative.length > 0) {
        const nIndex = Math.floor(signNegative.length * (1 - cutOffDist));
        initialNoiseLevelNegative = -1 * signNegative[nIndex];
      } else {
        initialNoiseLevelNegative = 0;
      }
      let noiseLevelPositive = initialNoiseLevelPositive;
      let noiseLevelNegative = initialNoiseLevelNegative;
      let cloneSignPositive = signPositive.slice();
      let cloneSignNegative = signNegative.slice();
      let cutOffSignalsIndexPlus = 0;
      let cutOffSignalsIndexNeg = 2;
      if (refine) {
        let cutOffSignals = noiseLevelPositive * factorStd;
        cutOffSignalsIndexPlus = signPositive.findIndex(e => e < cutOffSignals);
        if (cutOffSignalsIndexPlus > -1) {
          cloneSignPositive = signPositive.slice(cutOffSignalsIndexPlus);
          noiseLevelPositive = cloneSignPositive[Math.floor(cloneSignPositive.length * cutOffDist)];
        }
        cutOffSignals = noiseLevelNegative * factorStd;
        cutOffSignalsIndexNeg = signNegative.findIndex(e => e < cutOffSignals);
        if (cutOffSignalsIndexNeg > -1) {
          cloneSignNegative = signNegative.slice(cutOffSignalsIndexNeg);
          noiseLevelNegative = cloneSignPositive[Math.floor(cloneSignNegative.length * (1 - cutOffDist))];
        }
      }
      const correctionFactor = -simpleNormInvNumber(cutOffDist / 2, {
        magnitudeMode
      });
      let effectiveCutOffDist, refinedCorrectionFactor;
      if (refine && cutOffSignalsIndexPlus > -1) {
        effectiveCutOffDist = (cutOffDist * cloneSignPositive.length + cutOffSignalsIndexPlus) / (cloneSignPositive.length + cutOffSignalsIndexPlus);
        refinedCorrectionFactor = -1 * simpleNormInvNumber(effectiveCutOffDist / 2, {
          magnitudeMode
        });
        noiseLevelPositive /= refinedCorrectionFactor;
        if (cutOffSignalsIndexNeg > -1) {
          effectiveCutOffDist = (cutOffDist * cloneSignNegative.length + cutOffSignalsIndexNeg) / (cloneSignNegative.length + cutOffSignalsIndexNeg);
          refinedCorrectionFactor = -1 * simpleNormInvNumber(effectiveCutOffDist / 2, {
            magnitudeMode
          });
          if (noiseLevelNegative !== 0) {
            noiseLevelNegative /= refinedCorrectionFactor;
          }
        }
      } else {
        noiseLevelPositive /= correctionFactor;
        noiseLevelNegative /= correctionFactor;
      }
      return {
        positive: noiseLevelPositive,
        negative: noiseLevelNegative,
        snr: skyPoint / noiseLevelPositive,
        sanplot: generateSanPlot(input, {
          fromTo: {
            positive: {
              from: 0,
              to: lastPositiveValueIndex
            },
            negative: {
              from: firstNegativeValueIndex,
              to: input.length
            }
          }
        })
      };
    }
    /**
     * Determines the optimal cut-off point for a given array of positive numbers.
     * @param signPositive - An array of positive numbers.
     * @param options - Optional parameters to configure the cut-off determination.
     * @param options.magnitudeMode - If true, uses magnitude mode for normalization. Default is false.
     * @param options.considerList - An object specifying the range and step for consideration.
     * @param options.considerList.from - The starting point of the range. Default is 0.5.
     * @param options.considerList.step - The step size for the range. Default is 0.1.
     * @param options.considerList.to - The ending point of the range. Default is 0.9.
     * @returns The optimal cut-off point as a number.
     */
    function determineCutOff(signPositive, options = {}) {
      const {
        magnitudeMode = false,
        considerList = {
          from: 0.5,
          step: 0.1,
          to: 0.9
        }
      } = options;
      //generate a list of values for
      const cutOff = [];
      const indexMax = signPositive.length - 1;
      for (let i = 0.01; i <= 0.99; i += 0.01) {
        const index = Math.round(indexMax * i);
        const value = -signPositive[index] / simpleNormInvNumber(i / 2, {
          magnitudeMode
        });
        cutOff.push([i, value]);
      }
      let minKi = Number.MAX_SAFE_INTEGER;
      const {
        from,
        to,
        step
      } = considerList;
      const delta = step / 2;
      let whereToCutStat = 0.5;
      for (let i = from; i <= to; i += step) {
        const floor = i - delta;
        const top = i + delta;
        const elementsOfCutOff = cutOff.filter(e => e[0] < top && e[0] > floor);
        let averageValue = 0;
        for (const element of elementsOfCutOff) {
          averageValue += Math.abs(element[1]);
        }
        let kiSqrt = 0;
        for (const element of elementsOfCutOff) {
          kiSqrt += (element[1] - averageValue) ** 2;
        }
        if (kiSqrt < minKi) {
          minKi = kiSqrt;
          whereToCutStat = i;
        }
      }
      return whereToCutStat;
    }
    /**
     * Generates a SAN plot from the given array based on the specified options.
     * @param array - The input array of numbers to be processed.
     * @param options - An optional object containing configuration options.
     * @param options.logBaseY - The logarithmic base for the Y-axis. Defaults to 2.
     * @param options.fromTo - An object specifying the range for each key. Each key maps to an object with `from` and `to` properties.
     * @returns An object where each key maps to a DataXY object containing the processed data.
     */
    function generateSanPlot(array, options = {}) {
      const {
        fromTo,
        logBaseY = 2
      } = options;
      const sanplot = {};
      for (const key in fromTo) {
        const {
          from,
          to
        } = fromTo[key];
        sanplot[key] = from !== to ? scale(array.slice(from, to), {
          logBaseY
        }) : {
          x: [],
          y: []
        };
        if (key === 'negative') {
          sanplot[key].y.reverse();
        }
      }
      return sanplot;
    }
    /**
     * Scales the input array based on the provided options.
     * @param array - The input array to be scaled.
     * @param options - An optional object containing scaling options.
     * @param options.logBaseY - If provided, the array values will be scaled using the logarithm of this base.
     * @returns An object containing the scaled x and y arrays.
     */
    function scale(array, options = {}) {
      const {
        log10,
        abs
      } = Math;
      const {
        logBaseY
      } = options;
      if (logBaseY) {
        array = array.slice(0);
        const logOfBase = log10(logBaseY);
        for (let i = 0; i < array.length; i++) {
          array[i] = log10(abs(array[i])) / logOfBase;
        }
      }
      const xAxis = createFromToArray({
        from: 0,
        to: array.length - 1,
        length: array.length
      });
      return {
        x: xAxis,
        y: array
      };
    }
    /**
     * Prepares and processes the input data array based on the provided options.
     * @param array - The input array of numbers to be processed.
     * @param options - An object containing the following properties:
     *   - scaleFactor: A number by which to scale each element of the array.
     *   - mask: An optional array of the same length as the input array, where
     *           elements corresponding to `true` values will be excluded from processing.
     * @param options.scaleFactor
     * @param options.mask
     * @returns A new Float64Array containing the processed data, scaled by the
     *          scaleFactor and sorted in descending order.
     */
    function prepareData(array, options) {
      const {
        scaleFactor,
        mask
      } = options;
      const input = xEnsureFloat64(isAnyArray$1(mask) && mask.length === array.length ? array.filter((_e, i) => !mask[i]) : array);
      if (scaleFactor > 1) {
        for (let i = 0; i < input.length; i++) {
          input[i] *= scaleFactor;
        }
      }
      input.sort();
      input.reverse();
      return input;
    }

    /**
     * Determine noise level using MAD https://en.wikipedia.org/wiki/Median_absolute_deviation
     * Constant to convert mad to sd calculated using https://www.wolframalpha.com/input?i=sqrt%282%29+inverse+erf%280.5%29
     * This assumes a gaussian distribution of the noise
     * @param array
     * @returns noise level corresponding to one standard deviation
     */
    function xNoiseStandardDeviation(array) {
      const {
        mad,
        median
      } = xMedianAbsoluteDeviation(array);
      return {
        sd: mad / 0.6744897501960817,
        mad,
        median
      };
    }

    /**
     * Calculate the sum of the values
     * @param array - Object that contains property x (an ordered increasing array) and y (an array).
     * @param options - Options.
     * @returns XSum value on the specified range.
     */
    function xSum(array, options = {}) {
      xCheck(array);
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex(array, options);
      let sumValue = array[fromIndex];
      for (let i = fromIndex + 1; i <= toIndex; i++) {
        sumValue += array[i];
      }
      return sumValue;
    }

    /**
     * Divides the data with either the sum, the absolute sum or the maximum of the data
     * @param input - Array containing values
     * @param options - options
     * @returns - normalized data
     */
    function xNormed(input, options = {}) {
      const {
        algorithm = 'absolute',
        value = 1
      } = options;
      xCheck(input);
      const output = getOutputArray(options.output, input.length);
      if (input.length === 0) {
        throw new Error('input must not be empty');
      }
      switch (algorithm) {
        case 'absolute':
          {
            const absoluteSumValue = absoluteSum(input) / value;
            if (absoluteSumValue === 0) {
              throw new Error('trying to divide by 0');
            }
            for (let i = 0; i < input.length; i++) {
              output[i] = input[i] / absoluteSumValue;
            }
            return output;
          }
        case 'max':
          {
            const currentMaxValue = xMaxValue(input);
            if (currentMaxValue === 0) {
              throw new Error('trying to divide by 0');
            }
            const factor = value / currentMaxValue;
            for (let i = 0; i < input.length; i++) {
              output[i] = input[i] * factor;
            }
            return output;
          }
        case 'sum':
          {
            const sumFactor = xSum(input) / value;
            if (sumFactor === 0) {
              throw new Error('trying to divide by 0');
            }
            for (let i = 0; i < input.length; i++) {
              output[i] = input[i] / sumFactor;
            }
            return output;
          }
        default:
          throw new Error(`unknown algorithm: ${String(algorithm)}`);
      }
    }
    function absoluteSum(input) {
      let sumValue = 0;
      for (const value of input) {
        sumValue += Math.abs(value);
      }
      return sumValue;
    }

    /**
     * This function pads an array
     *s
     * @param array - the array that will be padded
     * @param options - options
     */
    function xPadding(array, options = {}) {
      const {
        size = 0,
        value = 0,
        algorithm
      } = options;
      xCheck(array);
      if (!algorithm) {
        return xEnsureFloat64(array);
      }
      const result = new Float64Array(array.length + size * 2);
      for (let i = 0; i < array.length; i++) {
        result[i + size] = array[i];
      }
      const fromEnd = size + array.length;
      const toEnd = 2 * size + array.length;
      switch (algorithm) {
        case 'value':
          for (let i = 0; i < size; i++) {
            result[i] = value;
          }
          for (let i = fromEnd; i < toEnd; i++) {
            result[i] = value;
          }
          break;
        case 'duplicate':
          for (let i = 0; i < size; i++) {
            result[i] = array[0];
          }
          for (let i = fromEnd; i < toEnd; i++) {
            result[i] = array.at(-1);
          }
          break;
        case 'circular':
          for (let i = 0; i < size; i++) {
            result[i] = array[(array.length - size % array.length + i) % array.length];
          }
          for (let i = 0; i < size; i++) {
            result[i + fromEnd] = array[i % array.length];
          }
          break;
        default:
          throw new Error(`unknown algorithm ${String(algorithm)}`);
      }
      return result;
    }

    /**
     * Pareto scaling, which uses the square root of standard deviation as the scaling factor, circumvents the amplification of noise by retaining a small portion of magnitude information.
     * Noda, I. (2008). Scaling techniques to enhance two-dimensional correlation spectra. Journal of Molecular Structure, 883, 216-227.
     * DOI: 10.1016/j.molstruc.2007.12.026
     * @param array - array of number
     */
    function xParetoNormalization(array) {
      xCheck(array);
      const result = new Float64Array(array.length);
      const sqrtSD = Math.sqrt(xStandardDeviation(array));
      for (let i = 0; i < array.length; i++) {
        result[i] = array[i] / sqrtSD;
      }
      return result;
    }

    /**
     * Function used to rescale data
     * @param input - input for the rescale
     * @param options - options
     * @returns rescaled data
     */
    function xRescale(input, options = {}) {
      xCheck(input);
      const output = getOutputArray(options.output, input.length);
      const currentMin = xMinValue(input);
      const currentMax = xMaxValue(input);
      if (currentMin === currentMax) {
        throw new RangeError('minimum and maximum input values are equal. Cannot rescale a constant array');
      }
      const {
        min = 0,
        max = 1
      } = options;
      if (min >= max) {
        throw new RangeError('min option must be smaller than max option');
      }
      const factor = (max - min) / (currentMax - currentMin);
      for (let i = 0; i < input.length; i++) {
        output[i] = (input[i] - currentMin) * factor + min;
      }
      return output;
    }

    /**
     * This function calculates a rolling average
     * @param array - array
     * @param fct - callback function that from an array returns a value
     * @param options - options
     */
    function xRolling(array, fct, options = {}) {
      xCheck(array);
      if (typeof fct !== 'function') {
        throw new TypeError('fct must be a function');
      }
      const {
        window = 5,
        padding = {}
      } = options;
      const {
        size = window - 1,
        algorithm,
        value
      } = padding;
      const padded = xPadding(array, {
        size,
        algorithm,
        value
      }); // ensure we get a copy and it is float64
      const newArray = [];
      for (let i = 0; i < padded.length - window + 1; i++) {
        // we will send a view to the original buffer
        newArray.push(fct(padded.subarray(i, i + window)));
      }
      return newArray;
    }

    /**
     * This function calculates a rolling average
     * @param array - array
     * @param options - option
     */
    function xRollingAverage(array, options = {}) {
      return xRolling(array, xMean, options);
    }

    /**
     * This function calculates a rolling average
     * @param array - array
     * @param options - options
     */
    function xRollingMedian(array, options = {}) {
      return xRolling(array, xMedian, options);
    }

    function matrixCheck(data) {
      if (data.length === 0 || data[0].length === 0) {
        throw new RangeError('matrix must contain data');
      }
      const firstLength = data[0].length;
      for (let i = 1; i < data.length; i++) {
        if (data[i].length !== firstLength) {
          throw new RangeError('all rows must has the same length');
        }
      }
    }

    /**
     * Get min and max Z.
     * @param matrix - matrix [rows][cols].
     */
    function matrixMinMaxZ(matrix) {
      matrixCheck(matrix);
      const nbRows = matrix.length;
      const nbColumns = matrix[0].length;
      let min = matrix[0][0];
      let max = matrix[0][0];
      for (let column = 0; column < nbColumns; column++) {
        for (let row = 0; row < nbRows; row++) {
          if (matrix[row][column] < min) min = matrix[row][column];
          if (matrix[row][column] > max) max = matrix[row][column];
        }
      }
      return {
        min,
        max
      };
    }

    /**
     * Verify that `data` is an object of x,y arrays.
     * Throws an error if it's not.
     * @param data
     * @param options
     * @param options.minLength
     */
    function xyCheck(data, options = {}) {
      const {
        minLength
      } = options;
      if (data === null || typeof data !== 'object' ||
      // @ts-expect-error Typechecking
      !isAnyArray$1(data.x) ||
      // @ts-expect-error Typechecking
      !isAnyArray$1(data.y)) {
        throw new Error('data must be an object of x and y arrays');
      }
      // @ts-expect-error Typechecking
      if (data.x.length !== data.y.length) {
        throw new Error('the x and y arrays must have the same length');
      }
      // @ts-expect-error Typechecking
      if (minLength && data.x.length < minLength) {
        throw new Error(`data.x must have a length of at least ${minLength}`);
      }
    }

    /**
     * Filters x,y values to allow strictly growing values in x-axis.
     * @param data - Object that contains property x (an ordered increasing array) and y (an array).
     */
    function xyEnsureGrowingX(data) {
      xyCheck(data);
      if (xIsMonotonic(data.x) === 1) return data;
      const x = Array.from(data.x);
      const y = Array.from(data.y);
      let prevX = Number.NEGATIVE_INFINITY;
      let currentIndex = 0;
      for (let index = 0; index < x.length; index++) {
        if (prevX < x[index]) {
          if (currentIndex < index) {
            x[currentIndex] = x[index];
            y[currentIndex] = y[index];
          }
          currentIndex++;
          prevX = x[index];
        }
      }
      x.length = currentIndex;
      y.length = currentIndex;
      return {
        x,
        y
      };
    }

    /**
     * Normalize an array of zones:
     * - ensure than from < to
     * - merge overlapping zones
     * - deal with exclusions zones
     * - if no zones is specified add one between -Infinity and +Infinity
     * @param zones - array of zones
     * @param options - options
     * @returns array of zones
     */
    function zonesNormalize(zones = [], options = {}) {
      const {
        exclusions = []
      } = options;
      let {
        from = Number.NEGATIVE_INFINITY,
        to = Number.POSITIVE_INFINITY
      } = options;
      if (from > to) [from, to] = [to, from];
      zones = zones.map(zone => zone.from > zone.to ? {
        from: zone.to,
        to: zone.from
      } : {
        ...zone
      });
      zones.sort((a, b) => {
        if (a.from !== b.from) return a.from - b.from;
        return a.to - b.to;
      });
      if (zones.length === 0) {
        zones.push({
          from,
          to
        });
      }
      for (const zone of zones) {
        if (from > zone.from) zone.from = from;
        if (to < zone.to) zone.to = to;
      }
      zones = zones.filter(zone => zone.from <= zone.to);
      if (zones.length === 0) return [];
      let currentZone = zones[0];
      const beforeExclusionsZones = [currentZone];
      for (let i = 1; i < zones.length; i++) {
        const zone = zones[i];
        if (zone.from <= currentZone.to) {
          if (currentZone.to < zone.to) {
            currentZone.to = zone.to;
          }
        } else {
          currentZone = zone;
          beforeExclusionsZones.push(currentZone);
        }
      }
      if (exclusions.length === 0) return beforeExclusionsZones;
      const normalizedExclusions = zonesNormalize(exclusions);
      let currentExclusionIndex = 0;
      const results = [];
      for (let zoneIndex = 0; zoneIndex < beforeExclusionsZones.length; zoneIndex++) {
        const zone = beforeExclusionsZones[zoneIndex];
        if (currentExclusionIndex === normalizedExclusions.length) {
          // we analysed all the exclusion zones
          results.push(zone);
          continue;
        }
        while (currentExclusionIndex < normalizedExclusions.length && normalizedExclusions[currentExclusionIndex].to <= zone.from) {
          currentExclusionIndex++;
        }
        if (currentExclusionIndex === normalizedExclusions.length) {
          // we analysed all the exclusion zones
          results.push(zone);
          continue;
        }
        if (zone.to < normalizedExclusions[currentExclusionIndex].from) {
          // no problems, not yet in exclusion
          results.push(zone);
          continue;
        }
        if (normalizedExclusions[currentExclusionIndex].to >= zone.to) {
          // could be totally excluded
          if (normalizedExclusions[currentExclusionIndex].from <= zone.from) {
            continue;
          }
          results.push({
            from: normalizedExclusions[currentExclusionIndex].to,
            to: zone.to
          });
        }
        // we cut in the middle, we need to create more zones, annoying !
        if (normalizedExclusions[currentExclusionIndex].from > zone.from) {
          results.push({
            from: zone.from,
            to: normalizedExclusions[currentExclusionIndex].from
          });
        }
        zone.from = normalizedExclusions[currentExclusionIndex].to;
        zoneIndex--;
      }
      return results;
    }

    /**
     * Add the number of points per zone to reach a specified total
     * @param zones - array of zones
     * @param numberOfPoints - total number of points to distribute between zones
     * @param options - options
     * @returns array of zones with points
     */
    function zonesWithPoints(zones = [],
    /**
     * total number of points to distribute between zones
     * @default 10
     */
    numberOfPoints = 10, options = {}) {
      if (zones.length === 0) return [];
      const normalizedZones = zonesNormalize(zones, options);
      const zonesWithNumberOfPoints = [];
      const totalSize = normalizedZones.reduce((previous, current) => {
        return previous + (current.to - current.from);
      }, 0);
      const unitsPerPoint = totalSize / numberOfPoints;
      let currentTotal = 0;
      for (let i = 0; i < normalizedZones.length - 1; i++) {
        const tempZone = normalizedZones[i];
        const tempZoneNumberOfPoints = Math.min(Math.round((tempZone.to - tempZone.from) / unitsPerPoint), numberOfPoints - currentTotal);
        zonesWithNumberOfPoints.push({
          ...tempZone,
          numberOfPoints: tempZoneNumberOfPoints
        });
        currentTotal += tempZoneNumberOfPoints;
      }
      zonesWithNumberOfPoints.push({
        ...normalizedZones.at(-1),
        numberOfPoints: numberOfPoints - currentTotal
      });
      return zonesWithNumberOfPoints;
    }

    /**
     * Function that retrieves the getEquallySpacedData with the variant "slot".
     * @param x
     * @param y
     * @param from
     * @param to
     * @param numberOfPoints
     * @returns Array of y's equally spaced with the variant "slot"
     */
    function equallySpacedSlot(/** x coordinates */
    x, /** y coordinates */
    y, /** from value */
    from, /** to value */
    to, /** number of points */
    numberOfPoints) {
      const xLength = x.length;
      if (xLength < 2) {
        return Float64Array.from(x);
      }
      const step = (to - from) / (numberOfPoints > 1 ? numberOfPoints - 1 : 1);
      const halfStep = step / 2;
      const lastStep = x.at(-1) - x.at(-2);
      const start = from - halfStep;
      // Changed Array to Float64Array
      const output = new Float64Array(numberOfPoints);
      // Init main variables
      let min = start;
      let max = start + step;
      let previousX = -Number.MAX_VALUE;
      let previousY = 0;
      let nextX = x[0];
      let nextY = y[0];
      let frontOutsideSpectra = 0;
      let backOutsideSpectra = true;
      let currentValue = 0;
      // for slot algorithm
      let currentPoints = 0;
      let i = 1; // index of input
      let j = 0; // index of output
      main: while (true) {
        if (previousX >= nextX) throw new Error('x must be a growing series');
        while (previousX - max > 0) {
          // no overlap with original point, just consume current value
          if (backOutsideSpectra) {
            currentPoints++;
            backOutsideSpectra = false;
          }
          output[j] = currentPoints <= 0 ? 0 : currentValue / currentPoints;
          j++;
          if (j === numberOfPoints) {
            break main;
          }
          min = max;
          max += step;
          currentValue = 0;
          currentPoints = 0;
        }
        if (previousX > min) {
          currentValue += previousY;
          currentPoints++;
        }
        if (previousX === -Number.MAX_VALUE || frontOutsideSpectra > 1) {
          currentPoints--;
        }
        previousX = nextX;
        previousY = nextY;
        if (i < xLength) {
          nextX = x[i];
          nextY = y[i];
          i++;
        } else {
          nextX += lastStep;
          nextY = 0;
          frontOutsideSpectra++;
        }
      }
      return output;
    }

    /**
     * Function that calculates the integral of the line between two
     * x-coordinates, given the slope and intercept of the line.
     * @param x0
     * @param x1
     * @param slope
     * @param intercept
     * @returns integral value.
     */
    function integral(/** first coordinate of point */
    x0, /** second coordinate of point */
    x1, /** slope of the line */
    slope, /** intercept of the line on the y axis */
    intercept) {
      return 0.5 * slope * x1 * x1 + intercept * x1 - (0.5 * slope * x0 * x0 + intercept * x0);
    }

    /**
     * Function that retrieves the getEquallySpacedData with the variant "smooth".
     * @param x
     * @param y
     * @param from
     * @param to
     * @param numberOfPoints
     * @returns - Array of y's equally spaced with the variant "smooth"
     */
    function equallySpacedSmooth(/** x coordinates */
    x, /** y coordinates */
    y, /** from value */
    from, /** to value */
    to, /** number of points */
    numberOfPoints) {
      const xLength = x.length;
      const step = (to - from) / (numberOfPoints > 1 ? numberOfPoints - 1 : 1);
      const halfStep = step / 2;
      // Changed Array to Float64Array
      const output = new Float64Array(numberOfPoints);
      const initialOriginalStep = x[1] - x[0];
      const lastOriginalStep = x[xLength - 1] - x[xLength - 2];
      // Init main variables
      let min = from - halfStep;
      let max = from + halfStep;
      let previousX = Number.MIN_SAFE_INTEGER;
      let previousY = 0;
      let nextX = x[0] - initialOriginalStep;
      let nextY = 0;
      let currentValue = 0;
      let slope = 0;
      let intercept = 0;
      let sumAtMin = 0;
      let sumAtMax = 0;
      let i = 0; // index of input
      let j = 0; // index of output
      let add = 0;
      main: while (true) {
        if (previousX >= nextX) throw new Error('x must be a growing series');
        if (previousX <= min && min <= nextX) {
          add = integral(0, min - previousX, slope, previousY);
          sumAtMin = currentValue + add;
        }
        while (nextX - max >= 0) {
          // no overlap with original point, just consume current value
          add = integral(0, max - previousX, slope, previousY);
          sumAtMax = currentValue + add;
          output[j++] = (sumAtMax - sumAtMin) / step;
          if (j === numberOfPoints) {
            break main;
          }
          min = max;
          max += step;
          sumAtMin = sumAtMax;
        }
        currentValue += integral(previousX, nextX, slope, intercept);
        previousX = nextX;
        previousY = nextY;
        if (i < xLength) {
          nextX = x[i];
          nextY = y[i];
          i++;
        } else if (i === xLength) {
          nextX += lastOriginalStep;
          nextY = 0;
        }
        slope = getSlope(previousX, previousY, nextX, nextY);
        intercept = -slope * previousX + previousY;
      }
      return output;
    }
    function getSlope(x0, y0, x1, y1) {
      return (y1 - y0) / (x1 - x0);
    }

    /**
     * Function that returns a Number array of equally spaced numberOfPoints
     * containing a representation of intensities of the spectra arguments x
     * and y.
     *
     * The options parameter contains an object in the following form:
     * from: starting point
     * to: last point
     * numberOfPoints: number of points between from and to
     * variant: "slot" or "smooth" - smooth is the default option
     *
     * The slot variant consist that each point in an array is calculated
     * averaging the existing points between the slot that belongs to the current
     * value. The smooth variant is the same but takes the integral of the range
     * of the slot and divide by the step size between two points in an array.
     *
     * If exclusions zone are present, zones are ignored !
     * @param data - object containing 2 properties x and y
     * @param options - options
     * @returns new object with x / y array with the equally spaced data.
     */
    function xyEquallySpaced(data, options = {}) {
      const {
        x,
        y
      } = data;
      const xLength = x.length;
      const {
        from = x[0],
        to = x[xLength - 1],
        variant = 'smooth',
        numberOfPoints = 100,
        exclusions = [],
        zones = [{
          from,
          to
        }]
      } = options;
      if (from > to) {
        throw new RangeError('from should be larger than to');
      }
      xyCheck(data);
      if (numberOfPoints < 2) {
        throw new RangeError("'numberOfPoints' option must be greater than 1");
      }
      const normalizedZones = zonesNormalize(zones, {
        from,
        to,
        exclusions
      });
      const zonesWithPointsRes = zonesWithPoints(normalizedZones, numberOfPoints, {
        from,
        to
      }).filter(zone => zone.numberOfPoints);
      let xResult = [];
      let yResult = [];
      for (const zone of zonesWithPointsRes) {
        if (!zone.numberOfPoints) {
          zone.numberOfPoints = 0;
        }
        const zoneResult = processZone(Array.from(x), Array.from(y), zone.from, zone.to, zone.numberOfPoints, variant);
        xResult = xResult.concat(zoneResult.x);
        yResult = yResult.concat(zoneResult.y);
      }
      return {
        x: xResult,
        y: yResult
      };
    }
    function processZone(x, y, from, to, numberOfPoints, variant) {
      if (numberOfPoints < 1) {
        throw new RangeError('the number of points must be at least 1');
      }
      const output = variant === 'slot' ? Array.from(equallySpacedSlot(x, y, from, to, numberOfPoints)) : Array.from(equallySpacedSmooth(x, y, from, to, numberOfPoints));
      return {
        x: Array.from(createFromToArray({
          from,
          to,
          length: numberOfPoints
        })),
        y: output
      };
    }

    /**
     * Filter an array x/y based on various criteria x points are expected to be sorted
     * @param data - object containing 2 properties x and y
     * @param options - options
     * @returns filtered array
     */
    function xyFilterX(data, options = {}) {
      const {
        x,
        y
      } = data;
      if (x.length === 0) {
        return {
          x: Array.from(x),
          y: Array.from(y)
        };
      }
      const {
        from = x[0],
        to = x.at(-1),
        zones = [{
          from,
          to
        }],
        exclusions = []
      } = options;
      const normalizedZones = zonesNormalize(zones, {
        from,
        to,
        exclusions
      });
      let currentZoneIndex = 0;
      const newX = [];
      const newY = [];
      let position = 0;
      while (position < x.length) {
        if (x[position] <= normalizedZones[currentZoneIndex].to && x[position] >= normalizedZones[currentZoneIndex].from) {
          newX.push(x[position]);
          newY.push(y[position]);
        } else if (x[position] > normalizedZones[currentZoneIndex].to) {
          currentZoneIndex++;
          if (!normalizedZones[currentZoneIndex]) break;
        }
        position++;
      }
      return {
        x: newX,
        y: newY
      };
    }

    /**
     * Filter out all the points for which x <= 0. Useful to display log scale data
     * @param data - data
     * @returns - An object with the filtered data
     */
    function xyFilterXPositive(data) {
      xyCheck(data);
      const {
        x,
        y
      } = data;
      const newX = [];
      const newY = [];
      if (x === undefined || y === undefined) {
        return {
          x: newX,
          y: newY
        };
      }
      for (let i = 0; i < x.length; i++) {
        if (x[i] > 0) {
          newX.push(x[i]);
          newY.push(y[i]);
        }
      }
      return {
        x: newX,
        y: newY
      };
    }

    /**
     * Order object of array, x has to be monotone. Ensure x is growing
     * @param data - Object of kind {x:[], y:[]}.
     */
    function xyGrowingX(data) {
      const {
        x,
        y
      } = data;
      if (x.length !== y.length) {
        throw new TypeError('length of x and y must be identical');
      }
      if (x.length < 2 || x[0] < x.at(-1)) return data;
      return {
        x: x.toReversed(),
        y: y.toReversed()
      };
    }

    /**
     * Join x / y values when difference in X is closer than delta.
     * When joining, y values are summed and x values are weighted average
     * @param data - Object that contains property x (an ordered increasing array) and y (an array)
     * @param options - Options
     * @returns - An object with the xyIntegration function
     */
    function xyJoinX(data, options = {}) {
      xyCheck(data);
      const {
        delta = 1
      } = options;
      const deltaIsFunction = typeof delta === 'function';
      const x = Array.from(data.x);
      const y = Array.from(data.y);
      if (x.length < 2) {
        return {
          x,
          y
        };
      }
      let position = 0;
      for (let i = 1; i < x.length; i++) {
        const difference = x[i] - x[i - 1];
        const currentDelta = deltaIsFunction ? delta((x[i] + x[i - 1]) / 2) : delta;
        if (difference <= currentDelta) {
          // we join
          if (y[position] !== 0 || y[i] !== 0) {
            x[position] = (x[position] * y[position] + x[i] * y[i]) / (y[position] + y[i]);
            y[position] += y[i];
          }
        } else {
          position++;
          x[position] = x[i];
          y[position] = y[i];
        }
      }
      x.length = position + 1;
      y.length = position + 1;
      return {
        x,
        y
      };
    }

    /**
     * GetSlots.
     * @param data - data.
     * @param options - Options.
     */
    function getSlots(data, options = {}) {
      const {
        delta = 1
      } = options;
      const deltaIsFunction = typeof delta === 'function';
      const possibleXs = Float64Array.from(data.flatMap(spectrum => spectrum.x));
      possibleXs.sort();
      if (possibleXs.length === 0) {
        throw new Error('can not process empty arrays');
      }
      let currentSlot = {
        from: possibleXs[0],
        to: possibleXs[0],
        average: possibleXs[0],
        sum: possibleXs[0],
        number: 1
      };
      const slots = [currentSlot];
      for (let i = 1; i < possibleXs.length; i++) {
        const currentDelta = deltaIsFunction ? delta(possibleXs[i]) : delta;
        if (possibleXs[i] - currentSlot.to <= currentDelta) {
          currentSlot.to = possibleXs[i];
          currentSlot.number++;
          currentSlot.sum += possibleXs[i];
          currentSlot.average = currentSlot.sum / currentSlot.number;
        } else {
          currentSlot = {
            from: possibleXs[i],
            to: possibleXs[i],
            average: possibleXs[i],
            sum: possibleXs[i],
            number: 1
          };
          slots.push(currentSlot);
        }
      }
      return slots;
    }

    /**
     * Aligns data, can be used for spectra
     * @param data - data
     * @param options - Options
     */
    function xyArrayAlign(data, options = {}) {
      const {
        delta = 1,
        requiredY = false
      } = options;
      data = data.map(spectrum => xyJoinX(spectrum, {
        delta
      }));
      const slots = getSlots(data, {
        delta
      });
      const x = Float64Array.from(slots.map(slot => slot.average));
      const ys = Array.from(data, () => new Float64Array(x.length));
      const positions = new Uint32Array(data.length);
      for (let i = 0; i < slots.length; i++) {
        const slot = slots[i];
        for (let j = 0; j < data.length; j++) {
          const spectrum = data[j];
          while (positions[j] < spectrum.x.length && spectrum.x[positions[j]] <= slot.to) {
            ys[j][i] += spectrum.y[positions[j]];
            positions[j]++;
          }
        }
      }
      if (requiredY) return filterRequiredY(x, ys);
      return {
        x,
        ys
      };
    }
    function filterRequiredY(x, ys) {
      const newX = [];
      const newYs = Array.from(ys, () => []);
      for (let i = 0; i < x.length; i++) {
        if (ys.every(y => y[i] !== 0)) {
          newX.push(x[i]);
          for (let j = 0; j < ys.length; j++) {
            newYs[j].push(ys[j][i]);
          }
        }
      }
      return {
        x: newX,
        ys: newYs
      };
    }

    function addStyle(serie, spectrum, options = {}) {
      let {
        color = '#A9A9A9'
      } = options;
      const {
        opacity = 1,
        lineWidth = 1
      } = options;
      if (color.match(/#[\da-f]{6}$/i)) {
        color = (color + (opacity * 255 >> 0).toString(16)).toUpperCase();
      } else {
        color = color.replace(/rgb ?\((.*)\)/, `rgba($1,${opacity})`);
      }
      serie.style = [{
        name: 'unselected',
        style: {
          line: {
            color,
            width: lineWidth,
            dash: 1
          }
        }
      }, {
        name: 'selected',
        style: {
          line: {
            color,
            width: lineWidth + 2,
            dash: 1
          }
        }
      }];
      serie.name = spectrum.label || spectrum.id;
    }

    const COLORS = ['#FFB300', '#803E75', '#FF6800', '#A6BDD7', '#C10020', '#CEA262', '#817066', '#007D34', '#F6768E', '#00538A', '#FF7A5C', '#53377A', '#FF8E00', '#B32851', '#F4C800', '#7F180D', '#93AA00', '#593315', '#F13A13', '#232C16'];

    /**
     * Generate a jsgraph chart format from an array of Analysis
     * @param analyses
     * @param options
     */
    function getJSGraph(analyses, options = {}) {
      const {
        colors = COLORS,
        opacities = [1],
        linesWidth = [1],
        selector = {},
        normalization,
        xAxis = {},
        yAxis = {}
      } = options;
      const series = [];
      let xLabel = xAxis.label;
      let yLabel = yAxis.label;
      let xUnits = xAxis.units;
      let yUnits = yAxis.units;
      for (let i = 0; i < analyses.length; i++) {
        const analysis = analyses[i];
        const spectra = analysis.getNormalizedSpectra({
          selector,
          normalization
        });
        if (spectra.length === 0) continue;
        const firstSpectrum = spectra[0];
        // todo: if many spectra are available and not xUnits / yUnits are specified we should ensure that all the spectra are compatible
        if (!xLabel) xLabel = firstSpectrum.variables.x.label;
        if (!yLabel) yLabel = firstSpectrum.variables.y.label;
        if (!xUnits) xUnits = firstSpectrum.variables.x.units;
        if (!yUnits) yUnits = firstSpectrum.variables.y.units;
        for (const spectrum of spectra) {
          const serie = {};
          addStyle(serie, analysis, {
            color: colors[i % colors.length],
            opacity: opacities[i % opacities.length],
            lineWidth: linesWidth[i % linesWidth.length]
          });
          serie.data = {
            x: spectrum.variables.x.data,
            y: spectrum.variables.y.data
          };
          serie.id = spectrum.id;
          if (xAxis.logScale) {
            serie.data = xyFilterXPositive(serie.data);
          }
          series.push(serie);
        }
      }
      return {
        axes: {
          x: {
            label: xLabel,
            unit: xUnits,
            unitWrapperBefore: '(',
            unitWrapperAfter: ')',
            flipped: false,
            display: true,
            ...xAxis
          },
          y: {
            label: yLabel,
            unit: yUnits,
            unitWrapperBefore: '(',
            unitWrapperAfter: ')',
            flipped: false,
            display: true,
            ...yAxis
          }
        },
        series
      };
    }

    const defaultBoundary = {
      y: {
        min: '0px',
        max: '2000px'
      }
    };
    function getNormalizationAnnotations(filter = {}, boundary = defaultBoundary) {
      let {
        exclusions = []
      } = filter;
      let annotations = [];
      exclusions = exclusions.filter(exclusion => !exclusion.ignore);
      annotations = exclusions.map(exclusion => {
        const annotation = {
          type: 'rect',
          position: [{
            x: exclusion.from,
            y: boundary.y.min
          }, {
            x: exclusion.to,
            y: boundary.y.max
          }],
          strokeWidth: 0,
          fillColor: 'rgba(255,255,224,1)'
        };
        return annotation;
      });
      if (filter.from !== undefined) {
        annotations.push({
          type: 'rect',
          position: [{
            x: Number.MIN_SAFE_INTEGER,
            y: boundary.y.min
          }, {
            x: filter.from,
            y: boundary.y.max
          }],
          strokeWidth: 0,
          fillColor: 'rgba(255,255,224,1)'
        });
      }
      if (filter.to !== undefined) {
        annotations.push({
          type: 'rect',
          position: [{
            x: filter.to,
            y: boundary.y.min
          }, {
            x: Number.MAX_SAFE_INTEGER,
            y: boundary.y.max
          }],
          strokeWidth: 0,
          fillColor: 'rgba(255,255,224,1)'
        });
      }
      return annotations;
    }

    /**
     * Center the mean
     * @param data
     */
    function centerMean(data) {
      const {
        y
      } = data;
      const mean = xMean(y);
      for (let i = 0; i < y.length; i++) {
        y[i] -= mean;
      }
      return {
        data
      };
    }

    /**
     * Center the median
     * @param data
     */
    function centerMedian(data) {
      const {
        y
      } = data;
      const median = xMedian(y);
      for (let i = 0; i < y.length; i++) {
        y[i] -= median;
      }
      return {
        data
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function fromTo(data, options = {}) {
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex(data.x, options);
      return {
        data: {
          x: data.x.subarray(fromIndex, toIndex + 1),
          y: data.y.subarray(fromIndex, toIndex + 1)
        }
      };
    }

    /**
     * Norm the Y values
     * @param data
     * @param options
     */
    function normed(data, options = {}) {
      xNormed(data.y, {
        ...options,
        output: data.y
      });
      return {
        data
      };
    }

    /**
     * Center the mean
     * @param data
     */
    function divideBySD(data) {
      const {
        y
      } = data;
      const sd = xStandardDeviation(y);
      for (let i = 0; i < y.length; i++) {
        y[i] /= sd;
      }
      return {
        data
      };
    }

    /**
     * Center the mean
     * @param data
     * @param options
     */
    function rescale(data, options = {}) {
      xRescale(data.y, {
        ...options,
        output: data.y
      });
      return {
        data
      };
    }

    /**
     * Filter that allows to
     * @param data
     */
    function paretoNormalization(data) {
      return {
        data: {
          x: data.x,
          y: xParetoNormalization(data.y)
        }
      };
    }

    // Based on https://github.com/scijs/cholesky-solve

    /*
    The MIT License (MIT)

    Copyright (c) 2013 Eric Arnebäck

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
    */

    function ldlSymbolic(n /* A and L are n-by-n, where n >= 0 */, Ap /* input of size n + 1, not modified */, Ai /* input of size nz=Ap[n], not modified */, Lp /* output of size n + 1, not defined on input */, Parent /* output of size n, not defined on input */, Lnz /* output of size n, not defined on input */, Flag /* workspace of size n, not defn. on input or output */) {
      let i, k, p, kk, p2;
      for (k = 0; k < n; k++) {
        /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */
        Parent[k] = -1; /* parent of k is not yet known */
        Flag[k] = k; /* mark node k as visited */
        Lnz[k] = 0; /* count of nonzeros in column k of L */
        kk = k; /* kth original, or permuted, column */
        p2 = Ap[kk + 1];
        for (p = Ap[kk]; p < p2; p++) {
          /* A (i,k) is nonzero (original or permuted A) */
          i = Ai[p];
          if (i < k) {
            /* follow path from i to root of etree, stop at flagged node */
            for (; Flag[i] !== k; i = Parent[i]) {
              /* find parent of i if not yet determined */
              if (Parent[i] === -1) Parent[i] = k;
              Lnz[i]++; /* L (k,i) is nonzero */
              Flag[i] = k; /* mark i as visited */
            }
          }
        }
      }
      /* construct Lp index array from Lnz column counts */
      Lp[0] = 0;
      for (k = 0; k < n; k++) {
        Lp[k + 1] = Lp[k] + Lnz[k];
      }
    }
    function ldlNumeric(n /* A and L are n-by-n, where n >= 0 */, Ap /* input of size n+1, not modified */, Ai /* input of size nz=Ap[n], not modified */, Ax /* input of size nz=Ap[n], not modified */, Lp /* input of size n+1, not modified */, Parent /* input of size n, not modified */, Lnz /* output of size n, not defn. on input */, Li /* output of size lnz=Lp[n], not defined on input */, Lx /* output of size lnz=Lp[n], not defined on input */, D /* output of size n, not defined on input */, Y /* workspace of size n, not defn. on input or output */, Pattern /* workspace of size n, not defn. on input or output */, Flag /* workspace of size n, not defn. on input or output */) {
      let yi, lKi;
      let i, k, p, kk, p2, len, top;
      for (k = 0; k < n; k++) {
        /* compute nonzero Pattern of kth row of L, in topological order */
        Y[k] = 0.0; /* Y(0:k) is now all zero */
        top = n; /* stack for pattern is empty */
        Flag[k] = k; /* mark node k as visited */
        Lnz[k] = 0; /* count of nonzeros in column k of L */
        kk = k; /* kth original, or permuted, column */
        p2 = Ap[kk + 1];
        for (p = Ap[kk]; p < p2; p++) {
          i = Ai[p]; /* get A(i,k) */
          if (i <= k) {
            Y[i] += Ax[p]; /* scatter A(i,k) into Y (sum duplicates) */
            for (len = 0; Flag[i] !== k; i = Parent[i]) {
              Pattern[len++] = i; /* L(k,i) is nonzero */
              Flag[i] = k; /* mark i as visited */
            }
            while (len > 0) Pattern[--top] = Pattern[--len];
          }
        }
        /* compute numerical values kth row of L (a sparse triangular solve) */
        D[k] = Y[k]; /* get D(k,k) and clear Y(k) */
        Y[k] = 0.0;
        for (; top < n; top++) {
          i = Pattern[top]; /* Pattern[top:n-1] is pattern of L(:,k) */
          yi = Y[i]; /* get and clear Y(i) */
          Y[i] = 0.0;
          p2 = Lp[i] + Lnz[i];
          for (p = Lp[i]; p < p2; p++) {
            Y[Li[p]] -= Lx[p] * yi;
          }
          lKi = yi / D[i]; /* the nonzero entry L(k,i) */
          D[k] -= lKi * yi;
          Li[p] = k; /* store L(k,i) in column form of L */
          Lx[p] = lKi;
          Lnz[i]++; /* increment count of nonzeros in col i */
        }
        if (D[k] === 0.0) return k; /* failure, D(k,k) is zero */
      }
      return n; /* success, diagonal of D is all nonzero */
    }
    function ldlLsolve(n /* L is n-by-n, where n >= 0 */, X /* size n. right-hand-side on input, soln. on output */, Lp /* input of size n+1, not modified */, Li /* input of size lnz=Lp[n], not modified */, Lx /* input of size lnz=Lp[n], not modified */) {
      let j, p, p2;
      for (j = 0; j < n; j++) {
        p2 = Lp[j + 1];
        for (p = Lp[j]; p < p2; p++) {
          X[Li[p]] -= Lx[p] * X[j];
        }
      }
    }
    function ldlDsolve(n /* D is n-by-n, where n >= 0 */, X /* size n. right-hand-side on input, soln. on output */, D /* input of size n, not modified */) {
      let j;
      for (j = 0; j < n; j++) {
        X[j] /= D[j];
      }
    }
    function ldlLTsolve(n /* L is n-by-n, where n >= 0 */, X /* size n. right-hand-side on input, soln. on output */, Lp /* input of size n+1, not modified */, Li /* input of size lnz=Lp[n], not modified */, Lx /* input of size lnz=Lp[n], not modified */) {
      let j, p, p2;
      for (j = n - 1; j >= 0; j--) {
        p2 = Lp[j + 1];
        for (p = Lp[j]; p < p2; p++) {
          X[j] -= Lx[p] * X[Li[p]];
        }
      }
    }
    function ldlPerm(n /* size of X, B, and P */, X /* output of size n. */, B /* input of size n. */, P /* input permutation array of size n. */) {
      let j;
      for (j = 0; j < n; j++) {
        X[j] = B[P[j]];
      }
    }
    function ldlPermt(n /* size of X, B, and P */, X /* output of size n. */, B /* input of size n. */, P /* input permutation array of size n. */) {
      let j;
      for (j = 0; j < n; j++) {
        X[P[j]] = B[j];
      }
    }
    function prepare(M, n, P) {
      // if a permutation was specified, apply it.
      if (P) {
        let Pinv = new Array(n);
        for (let k = 0; k < n; k++) {
          Pinv[P[k]] = k;
        }
        let Mt = []; // scratch memory
        // Apply permutation. We make M into P*M*P^T
        for (let a = 0; a < M.length; ++a) {
          let ar = Pinv[M[a][0]];
          let ac = Pinv[M[a][1]];

          // we only store the upper-diagonal elements(since we assume matrix is symmetric, we only need to store these)
          // if permuted element is below diagonal, we simply transpose it.
          if (ac < ar) {
            let t = ac;
            ac = ar;
            ar = t;
          }
          Mt[a] = [];
          Mt[a][0] = ar;
          Mt[a][1] = ac;
          Mt[a][2] = M[a][2];
        }
        M = Mt; // copy scratch memory.
      } else {
        // if P argument is null, we just use an identity permutation.
        P = [];
        for (let i = 0; i < n; ++i) {
          P[i] = i;
        }
      }

      // The sparse matrix we are decomposing is A.
      // Now we shall create A from M.
      let Ap = new Array(n + 1);
      let Ai = new Array(M.length);
      let Ax = new Array(M.length);

      // count number of non-zero elements in columns.
      let LNZ = [];
      for (let i = 0; i < n; ++i) {
        LNZ[i] = 0;
      }
      for (let a = 0; a < M.length; ++a) {
        LNZ[M[a][1]]++;
      }
      Ap[0] = 0;
      for (let i = 0; i < n; ++i) {
        Ap[i + 1] = Ap[i] + LNZ[i];
      }
      let coloffset = [];
      for (let a = 0; a < n; ++a) {
        coloffset[a] = 0;
      }

      // go through all elements in M, and add them to sparse matrix A.
      for (let i = 0; i < M.length; ++i) {
        let e = M[i];
        let col = e[1];
        let adr = Ap[col] + coloffset[col];
        Ai[adr] = e[0];
        Ax[adr] = e[2];
        coloffset[col]++;
      }
      let D = new Array(n);
      let Y = new Array(n);
      let Lp = new Array(n + 1);
      let Parent = new Array(n);
      let Lnz = new Array(n);
      let Flag = new Array(n);
      let Pattern = new Array(n);
      let bp1 = new Array(n);
      let x = new Array(n);
      let d;
      ldlSymbolic(n, Ap, Ai, Lp, Parent, Lnz, Flag);
      let Lx = new Array(Lp[n]);
      let Li = new Array(Lp[n]);
      d = ldlNumeric(n, Ap, Ai, Ax, Lp, Parent, Lnz, Li, Lx, D, Y, Pattern, Flag);
      if (d === n) {
        return b => {
          ldlPerm(n, bp1, b, P);
          ldlLsolve(n, bp1, Lp, Li, Lx);
          ldlDsolve(n, bp1, D);
          ldlLTsolve(n, bp1, Lp, Li, Lx);
          ldlPermt(n, x, bp1, P);
          return x;
        };
      } else {
        return null;
      }
    }

    var cuthillMckee_1 = cuthillMckee;
    function compareNum(a, b) {
      return a - b;
    }
    function cuthillMckee(list, n) {
      var adj = new Array(n);
      var visited = new Array(n);
      for (var i = 0; i < n; ++i) {
        adj[i] = [];
        visited[i] = false;
      }
      for (var i = 0; i < list.length; ++i) {
        var l = list[i];
        adj[l[0]].push(l[1]);
      }
      var toVisit = new Array(n);
      var eol = 0;
      var ptr = 0;
      for (var i = 0; i < n; ++i) {
        if (visited[i]) {
          continue;
        }
        toVisit[eol++] = i;
        visited[i] = true;
        while (ptr < eol) {
          var v = toVisit[ptr++];
          var nbhd = adj[v];
          nbhd.sort(compareNum);
          for (var j = 0; j < nbhd.length; ++j) {
            var u = nbhd[j];
            if (visited[u]) {
              continue;
            }
            visited[u] = true;
            toVisit[eol++] = u;
          }
        }
      }
      var result = new Array(n);
      for (var i = 0; i < n; ++i) {
        result[toVisit[i]] = i;
      }
      return result;
    }
    var cuthillMckee$1 = /*@__PURE__*/getDefaultExportFromCjs(cuthillMckee_1);

    const getClosestNumber = (array = [], goal = 0) => {
      const closest = array.reduce((prev, curr) => {
        return Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev;
      });
      return closest;
    };
    const getCloseIndex = (array = [], goal = 0) => {
      const closest = getClosestNumber(array, goal);
      return array.indexOf(closest);
    };
    const updateSystem = (matrix, y, weights) => {
      let nbPoints = y.length;
      let l = nbPoints - 1;
      let newMatrix = new Array(matrix.length);
      let newVector = new Float64Array(nbPoints);
      for (let i = 0; i < l; i++) {
        let w = weights[i];
        let diag = i * 2;
        let next = diag + 1;
        newMatrix[diag] = matrix[diag].slice();
        newMatrix[next] = matrix[next].slice();
        if (w === 0) {
          newVector[i] = 0;
        } else {
          newVector[i] = y[i] * w;
          newMatrix[diag][2] += w;
        }
      }
      newVector[l] = y[l] * weights[l];
      newMatrix[l * 2] = matrix[l * 2].slice();
      newMatrix[l * 2][2] += weights[l];
      return [newMatrix, newVector];
    };
    const getDeltaMatrix = (nbPoints, lambda) => {
      let matrix = [];
      let last = nbPoints - 1;
      for (let i = 0; i < last; i++) {
        matrix.push([i, i, lambda * 2]);
        matrix.push([i + 1, i, -1 * lambda]);
      }
      matrix[0][2] = lambda;
      matrix.push([last, last, lambda]);
      return {
        lowerTriangularNonZeros: matrix,
        permutationEncodedArray: cuthillMckee$1(matrix, nbPoints)
      };
    };

    function getControlPoints(x, y, options = {}) {
      const {
        length
      } = x;
      let {
        controlPoints = Int8Array.from({
          length
        }).fill(0)
      } = options;
      const {
        zones = [],
        weights = Float64Array.from({
          length
        }).fill(1)
      } = options;
      if (x.length !== y.length) {
        throw new RangeError('Y should match the length with X');
      } else if (controlPoints.length !== x.length) {
        throw new RangeError('controlPoints should match the length with X');
      } else if (weights.length !== x.length) {
        throw new RangeError('weights should match the length with X');
      }
      zones.forEach(range => {
        let indexFrom = getCloseIndex(x, range.from);
        let indexTo = getCloseIndex(x, range.to);
        if (indexFrom > indexTo) [indexFrom, indexTo] = [indexTo, indexFrom];
        for (let i = indexFrom; i < indexTo; i++) {
          controlPoints[i] = 1;
        }
      });
      return {
        weights: 'controlPoints' in options || zones.length > 0 ? xMultiply(weights, controlPoints) : weights,
        controlPoints
      };
    }

    /**
     * Fit the baseline drift by iteratively changing weights of sum square error between the fitted baseline and original signals,
     * for further information about the parameters you can get the [paper of airPLS](https://github.com/zmzhang/airPLS/blob/main/airPLS_manuscript.pdf)
     * @param {Array<number>} x - x axis data useful when control points or zones are submitted
     * @param {Array<number>} y - Original data
     * @param {object} [options={}] - Options object
     * @param {number} [options.maxIterations = 100] - Maximal number of iterations if the method does not reach the stop criterion
     * @param {number} [options.tolerance = 0.001] - Factor of the sum of absolute value of original data, to compute stop criterion
     * @param {Array<number>} [options.weights = [1,1,...]] - Initial weights vector, default each point has the same weight
     * @param {number} [options.lambda = 100] - Factor of weights matrix in -> [I + lambda D'D]z = x
     * @param {Array<number>} [options.controlPoints = []] - Array of 0|1 to force the baseline cross those points.
     * @param {Array<number>} [options.zones = []] - Array of x axis values (as from - to), to force that baseline cross those zones.
     * @returns {{corrected: Array<number>, error: number, iteration: number, baseline: Array<number>}}
     */

    function airPLS(x, y, options = {}) {
      const {
        weights,
        controlPoints
      } = getControlPoints(x, y, options);
      let {
        maxIterations = 100,
        lambda = 10,
        tolerance = 0.001
      } = options;
      let baseline, iteration;
      let sumNegDifferences = Number.MAX_SAFE_INTEGER;
      const corrected = Float64Array.from(y);
      let stopCriterion = getStopCriterion(y, tolerance);
      const {
        length
      } = y;
      let {
        lowerTriangularNonZeros,
        permutationEncodedArray
      } = getDeltaMatrix(length, lambda);
      let threshold = 1;
      const l = length - 1;
      let prevNegSum = Number.MAX_SAFE_INTEGER;
      for (iteration = 0; iteration < maxIterations && Math.abs(sumNegDifferences) > stopCriterion; iteration++) {
        let [leftHandSide, rightHandSide] = updateSystem(lowerTriangularNonZeros, y, weights);
        let cho = prepare(leftHandSide, length, permutationEncodedArray);
        baseline = cho(rightHandSide);
        sumNegDifferences = applyCorrection(y, baseline, corrected);
        if (iteration === 1) {
          const {
            positive
          } = xNoiseSanPlot(corrected);
          threshold = positive;
        } else {
          const absChange = Math.abs(prevNegSum / sumNegDifferences);
          if (absChange < 1.01 && absChange > 0.99) {
            break;
          }
        }
        prevNegSum = sumNegDifferences + 0;
        for (let i = 1; i < l; i++) {
          const diff = corrected[i];
          if (controlPoints[i] < 1 && Math.abs(diff) > threshold) {
            weights[i] = 0;
          } else {
            const factor = diff > 0 ? -1 : 1;
            weights[i] = Math.exp(factor * (iteration * diff) / Math.abs(sumNegDifferences));
          }
        }
        weights[0] = 1;
        weights[l] = 1;
      }
      return {
        corrected,
        baseline,
        iteration,
        error: sumNegDifferences
      };
      function applyCorrection(y, baseline, corrected) {
        let sumNegDifferences = 0;
        for (let i = 0; i < y.length; i++) {
          let diff = y[i] - baseline[i];
          if (diff < 0) sumNegDifferences += diff;
          corrected[i] = diff;
        }
        return sumNegDifferences;
      }
    }
    function getStopCriterion(y, tolerance) {
      let sum = xAbsoluteSum(y);
      return tolerance * sum;
    }

    function _typeof(obj) {
      "@babel/helpers - typeof";

      if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
        _typeof = function (obj) {
          return typeof obj;
        };
      } else {
        _typeof = function (obj) {
          return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
        };
      }
      return _typeof(obj);
    }

    /**
     * Fill an array with sequential numbers
     * @param {Array<number>} [input] - optional destination array (if not provided a new array will be created)
     * @param {object} [options={}]
     * @param {number} [options.from=0] - first value in the array
     * @param {number} [options.to=10] - last value in the array
     * @param {number} [options.size=input.length] - size of the array (if not provided calculated from step)
     * @param {number} [options.step] - if not provided calculated from size
     * @return {Array<number>}
     */

    function sequentialFill() {
      var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      if (_typeof(input) === 'object' && !isAnyArray$1(input)) {
        options = input;
        input = [];
      }
      if (!isAnyArray$1(input)) {
        throw new TypeError('input must be an array');
      }
      var _options = options,
        _options$from = _options.from,
        from = _options$from === void 0 ? 0 : _options$from,
        _options$to = _options.to,
        to = _options$to === void 0 ? 10 : _options$to,
        _options$size = _options.size,
        size = _options$size === void 0 ? input.length : _options$size,
        step = _options.step;
      if (size !== 0 && step) {
        throw new Error('step is defined by the array size');
      }
      if (!size) {
        if (step) {
          size = Math.floor((to - from) / step) + 1;
        } else {
          size = to - from + 1;
        }
      }
      if (!step && size) {
        step = (to - from) / (size - 1);
      }
      if (Array.isArray(input)) {
        // only works with normal array
        input.length = 0;
        for (var i = 0; i < size; i++) {
          input.push(from);
          from += step;
        }
      } else {
        if (input.length !== size) {
          throw new Error('sequentialFill typed array must have the correct length');
        }
        for (var _i = 0; _i < size; _i++) {
          input[_i] = from;
          from += step;
        }
      }
      return input;
    }

    /**
     * Adaptive iteratively reweighted penalized least squares [1]
     *
     * This function calls ml-airpls
     *
     * References:
     * [1] Zhang, Z.-M.; Chen, S.; Liang, Y.-Z.
     * Baseline Correction Using Adaptive Iteratively Reweighted Penalized Least Squares.
     * Analyst 2010, 135 (5), 1138–1146. https://doi.org/10.1039/B922045C.
     * @export
     * @param {Array<number>} ys
     * @param {object} [options] - Options object
     * @param {Array<number>} [options.x] Optional, Independent axis variable. If not specified, we use a linear grid
     * @param {object} [options.regression] - Options for the regression
     * @param {number} [options.regression.maxIterations = 100] - Maximum number of allowed iterations
     * @param {function} [options.regression.§Regression = PolynomialRegression] - Regression class with a predict method
     * @param {*} [options.regression.regressionOptions] - Options for regressionFunction
     * @param {number} [options.regression.tolerance = 0.001] - Convergence error tolerance
     * @returns {BaselineOutput}
     */
    function airPLSBaseline$1(ys, options = {}) {
      const numberPoints = ys.length;
      let {
        x,
        regressionOptions
      } = options;
      if (!x) {
        x = sequentialFill({
          from: 0,
          to: numberPoints - 1,
          size: numberPoints
        });
      }
      let output = airPLS(x, ys, regressionOptions);
      return {
        baseline: output.baseline,
        correctedSpectrum: output.corrected
      };
    }

    /**
     * Check that x and y are arrays with the same length.
     * @param x - first array
     * @param y - second array
     * @throws if x or y are not the same length, or if they are not arrays
     */
    function checkArrayLength(x, y) {
      if (!isAnyArray$1(x) || !isAnyArray$1(y)) {
        throw new TypeError('x and y must be arrays');
      }
      if (x.length !== y.length) {
        throw new RangeError('x and y arrays must have the same length');
      }
    }

    class BaseRegression {
      constructor() {
        if (new.target === BaseRegression) {
          throw new Error('BaseRegression must be subclassed');
        }
      }
      predict(x) {
        if (typeof x === 'number') {
          return this._predict(x);
        } else if (isAnyArray$1(x)) {
          const y = [];
          for (const xVal of x) {
            y.push(this._predict(xVal));
          }
          return y;
        } else {
          throw new TypeError('x must be a number or array');
        }
      }
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      _predict(x) {
        throw new Error('_predict must be implemented');
      }
      train() {
        // Do nothing for this package
      }
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      toString(precision) {
        return '';
      }
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      toLaTeX(precision) {
        return '';
      }
      /**
       * Return the correlation coefficient of determination (r) and chi-square.
       * @param x - explanatory variable
       * @param y - response variable
       * @return - Object with further statistics.
       */
      score(x, y) {
        checkArrayLength(x, y);
        const n = x.length;
        const y2 = new Array(n);
        for (let i = 0; i < n; i++) {
          y2[i] = this._predict(x[i]);
        }
        let xSum = 0;
        let ySum = 0;
        let chi2 = 0;
        let rmsd = 0;
        let xSquared = 0;
        let ySquared = 0;
        let xY = 0;
        for (let i = 0; i < n; i++) {
          xSum += y2[i];
          ySum += y[i];
          xSquared += y2[i] * y2[i];
          ySquared += y[i] * y[i];
          xY += y2[i] * y[i];
          if (y[i] !== 0) {
            chi2 += (y[i] - y2[i]) * (y[i] - y2[i]) / y[i];
          }
          rmsd += (y[i] - y2[i]) * (y[i] - y2[i]);
        }
        const r = (n * xY - xSum * ySum) / Math.sqrt((n * xSquared - xSum * xSum) * (n * ySquared - ySum * ySum));
        return {
          r,
          r2: r * r,
          chi2,
          rmsd: Math.sqrt(rmsd / n)
        };
      }
    }

    /**
     * Cast `number` to string. Optionally `digits` specifies significant figures.
     * @param number
     * @param figures
     * @returns - A string representation of `number`.
     */
    function maybeToPrecision(number, figures) {
      if (number < 0) {
        number = 0 - number;
        if (typeof figures === 'number') {
          return `- ${number.toPrecision(figures)}`;
        } else {
          return `- ${number.toString()}`;
        }
      } else if (typeof figures === 'number') {
        return number.toPrecision(figures);
      } else {
        return number.toString();
      }
    }

    class PolynomialRegression extends BaseRegression {
      /**
       * @param x - independent or explanatory variable
       * @param y - dependent or response variable
       * @param degree - degree of the polynomial regression, or array of powers to be used. When degree is an array, intercept at zero is forced to false/ignored.
       * @example `new PolynomialRegression(x, y, 2)`, in this case, you can pass the option `interceptAtZero`, if you need it.
       * @param options
       * @example `new PolynomialRegression(x, y, [1, 3, 5])`
       * Each of the degrees corresponds to a column, so if you have them switched, just do:
       * @example `new PolynomialRegression(x, y, [3, 1, 5])`
       * @param options.interceptAtZero - force the polynomial regression so that f(0) = 0
       */
      constructor(x, y, degree, options = {}) {
        super();
        // @ts-expect-error internal use only
        if (x === true) {
          // @ts-expect-error internal use only
          this.degree = y.degree;
          // @ts-expect-error internal use only
          this.powers = y.powers;
          // @ts-expect-error internal use only
          this.coefficients = y.coefficients;
        } else {
          checkArrayLength(x, y);
          const result = regress(x, y, degree, options);
          this.degree = result.degree;
          this.powers = result.powers;
          this.coefficients = result.coefficients;
        }
      }
      _predict(x) {
        let y = 0;
        for (let k = 0; k < this.powers.length; k++) {
          y += this.coefficients[k] * x ** this.powers[k];
        }
        return y;
      }
      toJSON() {
        return {
          name: 'polynomialRegression',
          degree: this.degree,
          powers: this.powers,
          coefficients: this.coefficients
        };
      }
      toString(precision) {
        return this._toFormula(precision, false);
      }
      toLaTeX(precision) {
        return this._toFormula(precision, true);
      }
      _toFormula(precision, isLaTeX) {
        let sup = '^';
        let closeSup = '';
        let times = ' * ';
        if (isLaTeX) {
          sup = '^{';
          closeSup = '}';
          times = '';
        }
        let fn = '';
        let str = '';
        for (let k = 0; k < this.coefficients.length; k++) {
          str = '';
          if (this.coefficients[k] !== 0) {
            if (this.powers[k] === 0) {
              str = maybeToPrecision(this.coefficients[k], precision);
            } else if (this.powers[k] === 1) {
              str = `${maybeToPrecision(this.coefficients[k], precision) + times}x`;
            } else {
              str = `${maybeToPrecision(this.coefficients[k], precision) + times}x${sup}${this.powers[k]}${closeSup}`;
            }
            if (this.coefficients[k] > 0 && k !== this.coefficients.length - 1) {
              str = ` + ${str}`;
            } else if (k !== this.coefficients.length - 1) {
              str = ` ${str}`;
            }
          }
          fn = str + fn;
        }
        if (fn.startsWith('+')) {
          fn = fn.slice(1);
        }
        return `f(x) = ${fn}`;
      }
      static load(json) {
        if (json.name !== 'polynomialRegression') {
          throw new TypeError('not a polynomial regression model');
        }
        // @ts-expect-error internal use only
        return new PolynomialRegression(true, json);
      }
    }
    /**
     * Perform a polynomial regression on the given data set.
     * This is an internal function.
     * @param x - independent or explanatory variable
     * @param y - dependent or response variable
     * @param degree - degree of the polynomial regression
     * @param options.interceptAtZero - force the polynomial regression so that $f(0) = 0$
     * @param options
     */
    function regress(x, y, degree, options = {}) {
      const n = x.length;
      let {
        interceptAtZero = false
      } = options;
      let powers = [];
      if (Array.isArray(degree)) {
        powers = degree;
        interceptAtZero = false; //must be false in this case
      } else if (typeof degree === 'number') {
        if (interceptAtZero) {
          powers = new Array(degree);
          for (let k = 0; k < degree; k++) {
            powers[k] = k + 1;
          }
        } else {
          powers = new Array(degree + 1);
          for (let k = 0; k <= degree; k++) {
            powers[k] = k;
          }
        }
      }
      const nCoefficients = powers.length; //1 per power, in any case.
      const F = new Matrix(n, nCoefficients);
      const Y = new Matrix([y]);
      for (let k = 0; k < nCoefficients; k++) {
        for (let i = 0; i < n; i++) {
          if (powers[k] === 0) {
            F.set(i, k, 1);
          } else {
            F.set(i, k, x[i] ** powers[k]);
          }
        }
      }
      const FT = new MatrixTransposeView(F);
      const A = FT.mmul(F);
      const B = FT.mmul(new MatrixTransposeView(Y));
      return {
        coefficients: solve(A, B).to1DArray(),
        degree: Math.max(...powers),
        powers
      };
    }

    /**
     * Iterative regression-based baseline correction
     * @param {Array<number>} x - Independent axis variable
     * @param {Array<number>} y - Dependent axis variable
     * @param {object} [options] - Options object
     * @param {number} [options.maxIterations = 100] - Maximum number of allowed iterations
     * @param {function} [options.Regression = PolynomialRegression] - Regression class with a predict method
     * @param {*} [options.regressionOptions] - Options for regressionFunction
     * @param {number} [options.tolerance = 0.001] - Convergence error tolerance
     * @return {{corrected: Array<number>, delta: number, iteration: number, baseline: Array<number>}}
     */
    function baselineCorrectionRegression(x, y, options = {}) {
      let {
        maxIterations = 100,
        Regression = PolynomialRegression,
        regressionOptions,
        tolerance = 0.001
      } = options;
      if (!regressionOptions && Regression === PolynomialRegression) {
        regressionOptions = 3;
      }
      let baseline = y.slice();
      let fitting = y.slice();
      let oldFitting = y;
      let iteration = 0;
      let delta;
      let regression;
      while (iteration < maxIterations) {
        // Calculate the fitting result
        regression = new Regression(x, baseline, regressionOptions);
        delta = 0;
        for (let i = 0; i < baseline.length; i++) {
          fitting[i] = regression.predict(x[i]);
          if (baseline[i] > fitting[i]) {
            baseline[i] = fitting[i];
          }
          delta += Math.abs((fitting[i] - oldFitting[i]) / oldFitting[i]);
        }

        // Stop criterion
        if (delta < tolerance) {
          break;
        } else {
          oldFitting = fitting.slice();
          iteration++;
        }
      }

      // removes baseline
      let corrected = new Array(baseline.length);
      for (let j = 0; j < baseline.length; j++) {
        corrected[j] = y[j] - baseline[j];
      }
      return {
        corrected,
        delta,
        iteration,
        baseline,
        regression
      };
    }

    /**
     * Iterative polynomial fitting [1]
     *
     * Implementation based on ml-baseline-correction-regression
     *
     * References:
     * [1] Gan, F.; Ruan, G.; Mo, J.
     * Baseline Correction by Improved Iterative Polynomial Fitting with Automatic Threshold.
     *  Chemometrics and Intelligent Laboratory Systems 2006, 82 (1), 59–65.
     * https://doi.org/10.1016/j.chemolab.2005.08.009.
     * @export
     * @param {Array<number>} ys
     * @param {object} [options] - Options object
     * @param {Array<number>} [options.x] Optional, Independent axis variable. If not specified, we use a linear grid
     * @param {Object} [options.regression]
     * @param {number} [options.regression.maxIterations = 100] - Maximum number of allowed iterations
     * @param {Object} [options.regression]
     * @param {function} [options.regression.Regression = PolynomialRegression] - Regression class with a predict method
     * @param {Object} [options.regression.regressionOptions] - Options for regressionFunction
     * @param {number} [options.regression.tolerance = 0.001] - Convergence error tolerance
     * @returns {BaselineOutput}
     */
    function iterativePolynomialBaseline$1(ys, options = {}) {
      const numberPoints = ys.length;
      let {
        x,
        regressionOptions
      } = options;
      if (!x) {
        x = sequentialFill({
          from: 0,
          to: numberPoints - 1,
          size: numberPoints
        });
      }
      let output = baselineCorrectionRegression(x, ys, regressionOptions);
      return {
        baseline: output.baseline,
        correctedSpectrum: output.corrected
      };
    }

    /**

     *
     * @export
     * @param {Array<number>} ys
     * @param {Object} [options={}]
     * @param {number} [options.window] rolling window size, defaults to 10% of the length of the spectrum
     * @param {string} [options.padding.size=window-1] none, value, circular, duplicate
     * @param {string} [options.padding.algorithm='duplicate'] none, value, circular, duplicate
     * @param {number} [options.padding.value=0] value to use for padding (if algorithm='value')
     * @returns {BaselineOutput}
     */
    function rollingAverageBaseline$1(ys, options = {}) {
      let window = Math.max(Math.round(ys.length * 0.1), 2);
      let defaults = {
        window,
        padding: {
          size: window - 1,
          algorithm: 'duplicate',
          value: 0
        }
      };
      let actualOptions = {
        ...defaults,
        ...options
      };
      let baseline = xRollingAverage(ys, actualOptions);
      let corrected = new Float64Array(ys.length);
      for (let i = 0; i < corrected.length; i++) {
        corrected[i] = ys[i] - baseline[i];
      }
      return {
        baseline,
        correctedSpectrum: corrected
      };
    }

    function rollingBall(spectrum, options = {}) {
      if (!isAnyArray$1(spectrum)) {
        throw new Error('Spectrum must be an array');
      }
      if (spectrum.length === 0) {
        throw new TypeError('Spectrum must not be empty');
      }
      const numberPoints = spectrum.length;
      const maxima = new Float64Array(numberPoints);
      const minima = new Float64Array(numberPoints);
      const baseline = new Float64Array(numberPoints);
      // windowM 4 percent of spectrum length
      // windowS 8 percent of spectrum length
      const {
        windowM = Math.round(numberPoints * 0.04),
        windowS = Math.round(numberPoints * 0.08)
      } = options;
      // fi(1) in original paper
      for (let i = 0; i < spectrum.length; i++) {
        const windowLeft = Math.max(0, i - windowM);
        const windowRight = Math.min(i + windowM + 1, spectrum.length);
        minima[i] = xMinValue(spectrum, {
          fromIndex: windowLeft,
          toIndex: windowRight
        });
      }
      // fi in original paper
      for (let i = 0; i < minima.length; i++) {
        const windowLeft = Math.max(0, i - windowM);
        const windowRight = Math.min(i + windowM + 1, minima.length);
        maxima[i] = xMaxValue(minima, {
          fromIndex: windowLeft,
          toIndex: windowRight
        });
      }
      for (let i = 0; i < minima.length; i++) {
        const windowLeft = Math.max(0, i - windowS);
        const windowRight = Math.min(i + windowS + 1, maxima.length);
        baseline[i] = xMean(maxima.subarray(windowLeft, windowRight));
      }
      return baseline;
    }

    /**
     * Rolling ball baseline correction algorithm.
     * From the abstract of (1):
     * "This algorithm behaves equivalently to traditional polynomial backgrounds in simple spectra,
     * [...] and is considerably more robust for multiple overlapping peaks, rapidly varying background [...]
     *
     * The baseline is the trace one gets by rolling a ball below a spectrum. Algorithm has three steps:
     * Finding the minima in each window, find maxima among minima and then smooth over them by averaging.
     *
     * Algorithm described in (1), but in the implementation here the window width does not change.
     *
     * Reference:
     * (1) Kneen, M. A.; Annegarn, H. J.
     *     Algorithm for Fitting XRF, SEM and PIXE X-Ray Spectra Backgrounds.
     *     Nuclear Instruments and Methods in Physics Research Section B: Beam Interactions with Materials and Atoms 1996, 109–110, 209–213.
     *     https://doi.org/10.1016/0168-583X(95)00908-6.
     * (2) Kristian Hovde Liland, Bjørn-Helge Mevik, Roberto Canteri: baseline.
     *     https://cran.r-project.org/web/packages/baseline/index.html
     *
     * @export
     * @param {Array<number>} ys
     * @param {Object} [options={}]
     * @param {Number} [options.windowM] - width of local window for minimization/maximization, defaults to 4% of the spectrum length
     * @param {Number} [options.windowS] - width of local window for smoothing, defaults to 8% of the specturm length
     * @returns {BaselineOutput}
     */
    function rollingBallBaseline$1(ys, options = {}) {
      const baseline = rollingBall(ys, options);
      let corrected = new Float64Array(ys.length);
      for (let i = 0; i < corrected.length; i++) {
        corrected[i] = ys[i] - baseline[i];
      }
      return {
        baseline,
        correctedSpectrum: corrected
      };
    }

    /**

     *
     * @export
     * @param {Array<number>} ys
     * @param {Object} [options={}]
     * @param {number} [options.window] rolling window size, defaults to 10% of the length of the spectrum
     * @param {string} [options.padding.size=window-1] none, value, circular, duplicate
     * @param {string} [options.padding.algorithm='duplicate'] none, value, circular, duplicate
     * @param {number} [options.padding.value=0] value to use for padding (if algorithm='value')
     * @returns {BaselineOutput}
     */
    function rollingMedianBaseline$1(ys, options = {}) {
      let window = Math.max(Math.round(ys.length * 0.1), 2);
      let defaults = {
        window,
        padding: {
          size: window - 1,
          algorithm: 'duplicate',
          value: 0
        }
      };
      let actualOptions = {
        ...defaults,
        ...options
      };
      let baseline = xRollingMedian(ys, actualOptions);
      let corrected = new Float64Array(ys.length);
      for (let i = 0; i < corrected.length; i++) {
        corrected[i] = ys[i] - baseline[i];
      }
      return {
        baseline,
        correctedSpectrum: corrected
      };
    }

    //@ts-expect-error no type definition for baselines
    /**
     * @param data
     */
    function airPLSBaseline(data) {
      data.y = airPLSBaseline$1(data.y).correctedSpectrum;
      return {
        data
      };
    }

    //@ts-expect-error no type definition for baselines
    /**
     * @param data
     */
    function iterativePolynomialBaseline(data) {
      data.y = iterativePolynomialBaseline$1(data.y).correctedSpectrum;
      return {
        data
      };
    }

    //@ts-expect-error no type definition for baselines
    /**
     * @param data
     */
    function rollingAverageBaseline(data) {
      data.y = rollingAverageBaseline$1(data.y).correctedSpectrum;
      return {
        data
      };
    }

    //@ts-expect-error no type definition for baselines
    /**
     * @param data
     */
    function rollingBallBaseline(data) {
      data.y = rollingBallBaseline$1(data.y).correctedSpectrum;
      return {
        data
      };
    }

    //@ts-expect-error no type definition for baselines
    /**
     * @param data
     */
    function rollingMedianBaseline(data) {
      data.y = rollingMedianBaseline$1(data.y).correctedSpectrum;
      return {
        data
      };
    }

    /**
     * Apply Savitzky Golay algorithm
     * @param [ys] Array of y values
     * @param [xs] Array of X or deltaX
     * @return  Array containing the new ys (same length)
     */
    function sgg(ys, xs, options = {}) {
      const {
        windowSize = 9,
        derivative = 0,
        polynomial = 3
      } = options;
      if (windowSize % 2 === 0 || windowSize < 5 || !Number.isInteger(windowSize)) {
        throw new RangeError('Invalid window size (should be odd and at least 5 integer number)');
      }
      if (!isAnyArray$1(ys)) {
        throw new TypeError('Y values must be an array');
      }
      if (typeof xs === 'undefined') {
        throw new TypeError('X must be defined');
      }
      if (windowSize > ys.length) {
        throw new RangeError(`Window size is higher than the data length ${windowSize}>${ys.length}`);
      }
      if (derivative < 0 || !Number.isInteger(derivative)) {
        throw new RangeError('Derivative should be a positive integer');
      }
      if (polynomial < 1 || !Number.isInteger(polynomial)) {
        throw new RangeError('Polynomial should be a positive integer');
      }
      if (polynomial >= 6) {
        // eslint-disable-next-line no-console
        console.warn('You should not use polynomial grade higher than 5 if you are' + ' not sure that your data arises from such a model. Possible polynomial oscillation problems');
      }
      const half = Math.floor(windowSize / 2);
      const np = ys.length;
      const ans = new Float64Array(np);
      const weights = fullWeights(windowSize, polynomial, derivative);
      let hs = 0;
      let constantH = true;
      if (isAnyArray$1(xs)) {
        constantH = false;
      } else {
        hs = xs ** derivative;
      }
      //For the borders
      for (let i = 0; i < half; i++) {
        const wg1 = weights[half - i - 1];
        const wg2 = weights[half + i + 1];
        let d1 = 0;
        let d2 = 0;
        for (let l = 0; l < windowSize; l++) {
          d1 += wg1[l] * ys[l];
          d2 += wg2[l] * ys[np - windowSize + l];
        }
        if (constantH) {
          ans[half - i - 1] = d1 / hs;
          ans[np - half + i] = d2 / hs;
        } else {
          hs = getHs(xs, half - i - 1, half, derivative);
          ans[half - i - 1] = d1 / hs;
          hs = getHs(xs, np - half + i, half, derivative);
          ans[np - half + i] = d2 / hs;
        }
      }
      //For the internal points
      const wg = weights[half];
      for (let i = windowSize; i <= np; i++) {
        let d = 0;
        for (let l = 0; l < windowSize; l++) d += wg[l] * ys[l + i - windowSize];
        if (!constantH) {
          hs = getHs(xs, i - half - 1, half, derivative);
        }
        ans[i - half - 1] = d / hs;
      }
      return ans;
    }
    function getHs(h, center, half, derivative) {
      let hs = 0;
      let count = 0;
      for (let i = center - half; i < center + half; i++) {
        if (i >= 0 && i < h.length - 1) {
          hs += h[i + 1] - h[i];
          count++;
        }
      }
      return (hs / count) ** derivative;
    }
    function gramPoly(i, m, k, s) {
      let Grampoly = 0;
      if (k > 0) {
        Grampoly = (4 * k - 2) / (k * (2 * m - k + 1)) * (i * gramPoly(i, m, k - 1, s) + s * gramPoly(i, m, k - 1, s - 1)) - (k - 1) * (2 * m + k) / (k * (2 * m - k + 1)) * gramPoly(i, m, k - 2, s);
      } else if (k === 0 && s === 0) {
        Grampoly = 1;
      } else {
        Grampoly = 0;
      }
      return Grampoly;
    }
    function genFact(a, b) {
      let gf = 1;
      if (a >= b) {
        for (let j = a - b + 1; j <= a; j++) {
          gf *= j;
        }
      }
      return gf;
    }
    function weight(i, t, m, n, s) {
      let sum = 0;
      for (let k = 0; k <= n; k++) {
        sum += (2 * k + 1) * (genFact(2 * m, k) / genFact(2 * m + k + 1, k + 1)) * gramPoly(i, m, k, 0) * gramPoly(t, m, k, s);
      }
      return sum;
    }
    /**
     * @private
     * @param m  Number of points
     * @param n  Polynomial grade
     * @param s  Derivative
     */
    function fullWeights(m, n, s) {
      const weights = new Array(m);
      const np = Math.floor(m / 2);
      for (let t = -np; t <= np; t++) {
        weights[t + np] = new Float64Array(m);
        for (let j = -np; j <= np; j++) {
          weights[t + np][j + np] = weight(j, t, np, n, s);
        }
      }
      return weights;
    }

    /**
     * Calculate the first derivative using Savitzky–Golay filter.
     * @param data
     * @param options
     */
    function firstDerivative$1(data, options = {}) {
      const {
        x,
        y
      } = data;
      return {
        data: {
          x,
          y: sgg(y, x, {
            ...options,
            derivative: 1
          })
        }
      };
    }

    /**
     * Calculate the second derivative using Savitzky–Golay filter.
     * @param data
     * @param options
     */
    function secondDerivative$1(data, options = {}) {
      const {
        x,
        y
      } = data;
      return {
        data: {
          x,
          y: sgg(y, x, {
            ...options,
            derivative: 2
          })
        }
      };
    }

    /**
     * Calculate the third derivative using Savitzky–Golay filter.
     * @param data
     * @param options
     */
    function thirdDerivative(data, options = {}) {
      const {
        x,
        y
      } = data;
      return {
        data: {
          x,
          y: sgg(y, x, {
            ...options,
            derivative: 3
          })
        }
      };
    }

    /**
     * Apply the Savitzky Golay Generalized Filter
     * @param data
     * @param options
     */
    function savitzkyGolay(data, options = {}) {
      const {
        x,
        y
      } = data;
      return {
        data: {
          x,
          y: sgg(y, x, options)
        }
      };
    }

    /**
     * Ensure X values are strictly monotonic increasing
     * http://www-groups.mcs.st-andrews.ac.uk/~john/analysis/Lectures/L8.html
     * @param data
     */
    function ensureGrowing(data) {
      return {
        data: xyEnsureGrowingX(data)
      };
    }

    /**
     * Ensure X values are strictly monotonic increasing
     * http://www-groups.mcs.st-andrews.ac.uk/~john/analysis/Lectures/L8.html
     * @param data
     */
    function reverseIfNeeded(data) {
      return {
        data: xyGrowingX(data)
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function equallySpaced(data, options = {}) {
      return {
        data: xyEquallySpaced(data, options)
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function filterX(data, options = {}) {
      return {
        data: xyFilterX(data, options)
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function setMaxX(data, options = {}) {
      const {
        max = 1
      } = options;
      const existingMax = xMaxValue(data.x);
      if (existingMax === max) {
        return {
          data
        };
      }
      return {
        data: {
          x: xAdd(data.x, max - existingMax),
          y: data.y
        }
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function setMinX(data, options = {}) {
      const {
        min = 0
      } = options;
      const existingMin = xMinValue(data.x);
      if (existingMin === min) {
        return {
          data
        };
      }
      return {
        data: {
          x: xAdd(data.x, min - existingMin),
          y: data.y
        }
      };
    }

    function getMinMaxIntervalsDy(y, x, dY, dX) {
      let lastMax = null;
      let lastMin = null;
      const intervalL = [];
      const intervalR = [];
      for (let i = 1; i < y.length - 1; ++i) {
        if (dY[i] < dY[i - 1] && dY[i] <= dY[i + 1] || dY[i] <= dY[i - 1] && dY[i] < dY[i + 1]) {
          lastMin = {
            x: x[i],
            index: i
          };
          if (dX > 0 && lastMax !== null) {
            intervalL.push(lastMax);
            intervalR.push(lastMin);
          }
        }
        // Maximum in first derivative
        if (dY[i] >= dY[i - 1] && dY[i] > dY[i + 1] || dY[i] > dY[i - 1] && dY[i] >= dY[i + 1]) {
          lastMax = {
            x: x[i],
            index: i
          };
          if (dX < 0 && lastMin !== null) {
            intervalL.push(lastMax);
            intervalR.push(lastMin);
          }
        }
      }
      return {
        intervalL,
        intervalR
      };
    }

    function tryMatchOneIntervalWithMinData(options) {
      const {
        x,
        lastK,
        minData,
        yThreshold,
        intervalWidth,
        intervalCenter,
        yData
      } = options;
      let minDistance = Number.POSITIVE_INFINITY;
      let possible = -1;
      let newLastIndex = lastK;
      for (let k = newLastIndex + 1; k < minData.length; k++) {
        const centerIndex = minData[k];
        if (yData[centerIndex] <= yThreshold) {
          continue;
        }
        const deltaX = x[centerIndex];
        const currentDistance = Math.abs(deltaX - intervalCenter);
        if (currentDistance < intervalWidth) {
          if (currentDistance < minDistance) {
            possible = k;
          }
          newLastIndex = k;
        }
        if (currentDistance >= minDistance) break;
        minDistance = currentDistance;
      }
      return {
        lastIndex: newLastIndex,
        possible
      };
    }

    function autoAlgorithm(input) {
      const {
        x,
        y,
        yData,
        dY,
        ddY,
        dX,
        yThreshold
      } = input;
      const minddY = [];
      const crossDy = [];
      const {
        intervalL,
        intervalR
      } = getMinMaxIntervalsDy(y, x, dY, dX);
      for (let i = 1; i < y.length - 1; ++i) {
        if (dY[i] < 0 && dY[i + 1] > 0 || dY[i] > 0 && dY[i + 1] < 0) {
          // push the index of the element closer to zero
          crossDy.push(Math.abs(dY[i]) < Math.abs(dY[i + 1]) ? i : i + 1);
        }
        // Handle exact zero
        if (dY[i] === 0 && dY[i] < Math.abs(dY[i + 1]) && dY[i] < Math.abs(dY[i - 1])) {
          crossDy.push(i);
        }
        // Minimum in second derivative
        if (ddY[i] < ddY[i - 1] && ddY[i] < ddY[i + 1]) {
          minddY.push(i);
        }
      }
      const peaks = [];
      let [lastK, lastJ] = [-1, -1];
      for (let i = 0; i < intervalL.length; i++) {
        const intervalWidth = (intervalR[i].x - intervalL[i].x) / 2;
        const intervalCenter = (intervalR[i].x + intervalL[i].x) / 2;
        let yIndex = -1;
        let match = tryMatchOneIntervalWithMinData({
          x,
          yData,
          lastK,
          yThreshold,
          intervalWidth,
          intervalCenter,
          minData: crossDy
        });
        lastK = match.lastIndex;
        if (match.possible !== -1) {
          yIndex = crossDy[match.possible];
        } else {
          match = tryMatchOneIntervalWithMinData({
            x,
            yData,
            yThreshold,
            lastK: lastJ,
            intervalWidth,
            intervalCenter,
            minData: minddY
          });
          if (match.possible !== -1) {
            yIndex = minddY[match.possible];
          }
          lastJ = match.lastIndex;
        }
        if (yIndex !== -1) {
          const width = Math.abs(intervalR[i].x - intervalL[i].x);
          peaks.push({
            id: crypto.randomUUID(),
            x: x[yIndex],
            y: y[yIndex],
            width,
            index: yIndex,
            ddY: ddY[yIndex],
            inflectionPoints: {
              from: intervalL[i],
              to: intervalR[i]
            }
          });
        }
      }
      return peaks;
    }

    function getPeakFromIntervals(options) {
      let lastK = -1;
      const peaks = [];
      const {
        x,
        ddY,
        yData,
        yThreshold,
        intervalR,
        intervalL,
        minData
      } = options;
      for (let i = 0; i < intervalL.length; i++) {
        const intervalWidth = (intervalR[i].x - intervalL[i].x) / 2;
        const intervalCenter = (intervalR[i].x + intervalL[i].x) / 2;
        const {
          possible = -1,
          lastIndex
        } = tryMatchOneIntervalWithMinData({
          x,
          lastK,
          minData,
          yThreshold,
          intervalWidth,
          intervalCenter,
          yData
        });
        if (possible !== -1) {
          const centerIndex = minData[possible];
          const width = Math.abs(intervalR[i].x - intervalL[i].x);
          peaks.push({
            id: crypto.randomUUID(),
            x: x[centerIndex],
            y: yData[centerIndex],
            width,
            index: centerIndex,
            ddY: ddY[centerIndex],
            inflectionPoints: {
              from: intervalL[i],
              to: intervalR[i]
            }
          });
        }
        lastK = lastIndex;
      }
      return peaks;
    }

    /**
     * Finds the indices where the first derivative crosses zero (sign change),
     * which are potential peak positions. This function does not detect zero-crossings
     * in regions with consecutive zero values in the derivative (flat regions).
     *
     * @param input - Object containing the y values and their first derivative (dY).
     * @returns Array of indices where the first derivative crosses zero (excluding consecutive zeros).
     */
    function xGetCrossZeroPoints(input) {
      const {
        y,
        dY
      } = input;
      const crossDy = [];
      for (let i = 1; i < y.length - 1; ++i) {
        if (isLessAndGreaterThanZero(dY[i], dY[i + 1])) {
          // push the index of the element closer to zero
          crossDy.push(Math.abs(dY[i]) < Math.abs(dY[i + 1]) ? i : i + 1);
        } else if (
        // Handle exact zero
        dY[i] === 0 && isLessAndGreaterThanZero(dY[i - 1], dY[i + 1])) {
          crossDy.push(i);
        }
      }
      return crossDy;
    }
    function isLessAndGreaterThanZero(back, next) {
      return back < 0 && next > 0 || back > 0 && next < 0;
    }

    function firstDerivative(input) {
      const {
        y,
        x,
        dY,
        dX,
        yData,
        yThreshold,
        ddY
      } = input;
      const crossDy = xGetCrossZeroPoints(input);
      const {
        intervalL,
        intervalR
      } = getMinMaxIntervalsDy(y, x, dY, dX);
      return getPeakFromIntervals({
        minData: crossDy,
        intervalL,
        intervalR,
        x,
        yData,
        yThreshold,
        ddY
      });
    }

    function secondDerivative(input) {
      const {
        x,
        y,
        yData,
        dY,
        ddY,
        dX,
        yThreshold
      } = input;
      const minddY = [];
      const {
        intervalL,
        intervalR
      } = getMinMaxIntervalsDy(y, x, dY, dX);
      // By the intermediate value theorem We cannot find 2 consecutive maximum or minimum
      for (let i = 1; i < y.length - 1; ++i) {
        // Minimum in second derivative
        if (ddY[i] < ddY[i - 1] && ddY[i] < ddY[i + 1]) {
          minddY.push(i);
        }
      }
      return getPeakFromIntervals({
        minData: minddY,
        intervalL,
        intervalR,
        x,
        yData,
        yThreshold,
        ddY
      });
    }

    /**
     * Correction of the x and y coordinates using a quadratic optimizations with the peak and its 3 closest neighbors to determine the true x,y values of the peak.
     * This process is done in place and is very fast.
     * @param data
     * @param peaks
     */
    function optimizeTop(data, peaks) {
      const {
        x,
        y
      } = data;
      for (const peak of peaks) {
        let currentIndex = peak.index;
        // The detected peak could be moved 1 or 2 units to left or right.
        if (y[currentIndex - 1] >= y[currentIndex - 2] && y[currentIndex - 1] >= y[currentIndex]) {
          currentIndex--;
        } else if (y[currentIndex + 1] >= y[currentIndex] && y[currentIndex + 1] >= y[currentIndex + 2]) {
          currentIndex++;
        } else if (y[currentIndex - 2] >= y[currentIndex - 3] && y[currentIndex - 2] >= y[currentIndex - 1]) {
          currentIndex -= 2;
        } else if (y[currentIndex + 2] >= y[currentIndex + 1] && y[currentIndex + 2] >= y[currentIndex + 3]) {
          currentIndex += 2;
        }
        // interpolation to a sin() function
        if (y[currentIndex - 1] > 0 && y[currentIndex + 1] > 0 && y[currentIndex] >= y[currentIndex - 1] && y[currentIndex] >= y[currentIndex + 1] && (y[currentIndex] !== y[currentIndex - 1] || y[currentIndex] !== y[currentIndex + 1])) {
          const alpha = 20 * Math.log10(y[currentIndex - 1]);
          const beta = 20 * Math.log10(y[currentIndex]);
          const gamma = 20 * Math.log10(y[currentIndex + 1]);
          const p = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma);
          const xCurrent = x[currentIndex];
          const xPrevious = x[currentIndex - 1];
          peak.x = xCurrent + (xCurrent - xPrevious) * p;
          peak.y = y[currentIndex] - 0.25 * (y[currentIndex - 1] - y[currentIndex + 1]) * p;
        }
      }
    }

    /**
     * Global spectra deconvolution
     * @param  data - Object data with x and y arrays. Values in x has to be growing
     * @param options
     * @param {number} [options.broadRatio = 0.00] - If `broadRatio` is higher than 0, then all the peaks which second derivative
     * smaller than `broadRatio * maxAbsSecondDerivative` will be marked with the soft mask equal to true.
     */
    function gsd(data, options = {}) {
      let {
        noiseLevel
      } = options;
      const {
        sgOptions = {
          windowSize: 9,
          polynomial: 3
        },
        smoothY = false,
        maxCriteria = true,
        minMaxRatio = 0.00025,
        realTopDetection = false,
        peakDetectionAlgorithm = 'second'
      } = options;
      const {
        x
      } = data;
      let {
        y
      } = data;
      if (xIsMonotonic(x) !== 1) {
        throw new Error('GSD only accepts monotone increasing x values');
      }
      //rescale;
      y = y.slice();
      // If the max difference between delta x is less than 5%, then,
      // we can assume it to be equally spaced variable
      const isEquallySpaced = xIsEquallySpaced(x);
      if (noiseLevel === undefined) {
        if (isEquallySpaced) {
          const noiseInfo = xNoiseStandardDeviation(y);
          if (maxCriteria) {
            noiseLevel = noiseInfo.median + 1.5 * noiseInfo.sd;
          } else {
            noiseLevel = -noiseInfo.median + 1.5 * noiseInfo.sd;
          }
        } else {
          noiseLevel = 0;
        }
      } else if (!maxCriteria) {
        noiseLevel *= -1;
      }
      if (!maxCriteria) {
        for (let i = 0; i < y.length; i++) {
          y[i] *= -1;
        }
      }
      if (noiseLevel !== undefined) {
        for (let i = 0; i < y.length; i++) {
          if (y[i] < noiseLevel) {
            y[i] = noiseLevel;
          }
        }
      }
      const xValue = isEquallySpaced ? x[1] - x[0] : x;
      const yData = smoothY ? sgg(y, xValue, {
        ...sgOptions,
        derivative: 0
      }) : y;
      const {
        min: minY,
        max: maxY
      } = xMinMaxValues(yData);
      if (minY > maxY || minY === maxY) return [];
      const dY = sgg(y, xValue, {
        ...sgOptions,
        derivative: 1
      });
      const ddY = sgg(y, xValue, {
        ...sgOptions,
        derivative: 2
      });
      const yThreshold = Math.max(noiseLevel, minY + (maxY - minY) * minMaxRatio);
      const dX = x[1] - x[0];
      const peakData = {
        x,
        y,
        yData,
        dY,
        ddY,
        dX,
        yThreshold
      };
      let peaks = [];
      if (peakDetectionAlgorithm === 'first') {
        peaks = firstDerivative(peakData);
      } else if (peakDetectionAlgorithm === 'second') {
        peaks = secondDerivative(peakData);
      } else {
        peaks = autoAlgorithm(peakData);
      }
      if (realTopDetection) {
        optimizeTop({
          x,
          y: yData
        }, peaks);
      }
      peaks.forEach(peak => {
        if (!maxCriteria) {
          peak.y *= -1;
          peak.ddY = peak.ddY * -1;
        }
      });
      peaks.sort((a, b) => {
        return a.x - b.x;
      });
      return peaks;
    }

    /**
     * Filter that allows to calibrateX the x axis based on the presence of peaks
     * @param data
     * @param options
     */
    function calibrateX(data, options = {}) {
      const {
        targetX = 0,
        nbPeaks = 1,
        from = data.x[0],
        to = data.x.at(-1),
        gsd: gsdOptions = {
          minMaxRatio: 0.1,
          realTopDetection: true,
          smoothY: true,
          sgOptions: {
            windowSize: 7,
            polynomial: 3
          }
        }
      } = options;
      const fromIndex = xFindClosestIndex(data.x, from);
      const toIndex = xFindClosestIndex(data.x, to);
      let peaks = gsd({
        x: data.x.subarray(fromIndex, toIndex),
        y: data.y.subarray(fromIndex, toIndex)
      }, gsdOptions);
      peaks.sort((a, b) => b.y - a.y);
      peaks = peaks.slice(0, nbPeaks);
      if (peaks.length < nbPeaks) return {
        data
      };
      const middle = xMean(peaks.map(peak => peak.x));
      return {
        data: {
          x: xAdd(data.x, targetX - middle),
          y: data.y
        }
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function xFunction(data, options = {}) {
      return {
        data: {
          x: xApplyFunctionStr(data.x, {
            variableLabel: 'x',
            fctString: options.function
          }),
          y: data.y
        }
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function yFunction(data, options = {}) {
      return {
        data: {
          x: data.x,
          y: xApplyFunctionStr(data.y, {
            variableLabel: 'y',
            fctString: options.function
          })
        }
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function setMaxY(data, options = {}) {
      const {
        max = 1
      } = options;
      const existingMax = xMaxValue(data.y);
      if (existingMax === max) {
        return {
          data
        };
      }
      return {
        data: {
          x: data.x,
          y: xAdd(data.y, max - existingMax)
        }
      };
    }

    /**
     * Filter that allows to
     * @param data
     * @param options
     */
    function setMinY(data, options = {}) {
      const {
        min = 0
      } = options;
      const existingMin = xMinValue(data.y);
      if (existingMin === min) {
        return {
          data
        };
      }
      return {
        data: {
          x: data.x,
          y: xAdd(data.y, min - existingMin)
        }
      };
    }

    var Filters = /*#__PURE__*/Object.freeze({
        __proto__: null,
        airPLSBaseline: airPLSBaseline,
        calibrateX: calibrateX,
        centerMean: centerMean,
        centerMedian: centerMedian,
        divideBySD: divideBySD,
        ensureGrowing: ensureGrowing,
        equallySpaced: equallySpaced,
        filterX: filterX,
        firstDerivative: firstDerivative$1,
        fromTo: fromTo,
        iterativePolynomialBaseline: iterativePolynomialBaseline,
        normed: normed,
        paretoNormalization: paretoNormalization,
        rescale: rescale,
        reverseIfNeeded: reverseIfNeeded,
        rollingAverageBaseline: rollingAverageBaseline,
        rollingBallBaseline: rollingBallBaseline,
        rollingMedianBaseline: rollingMedianBaseline,
        savitzkyGolay: savitzkyGolay,
        secondDerivative: secondDerivative$1,
        setMaxX: setMaxX,
        setMaxY: setMaxY,
        setMinX: setMinX,
        setMinY: setMinY,
        thirdDerivative: thirdDerivative,
        xFunction: xFunction,
        yFunction: yFunction
    });

    /**
     * Apply filters on {x:[], y:[]}
     * @param data
     * @param filters
     * @returns
     */
    function filterXY(data, filters) {
      let result = {
        data: xyGrowingX({
          x: xEnsureFloat64(data.x),
          y: xEnsureFloat64(data.y)
        })
      };
      const logs = [];
      for (const filter of filters) {
        const start = Date.now();
        if (!filter.name) {
          // we ignore empty filter names
          continue;
        }
        const filterFct = Filters[filter.name];
        if (!filterFct) {
          throw new Error(`Unknown filter: ${filter.name}`);
        }
        // @ts-expect-error some method have options and some other ones don't have any options
        result = filterFct(result.data, filter.options);
        result.data = xyGrowingX(result.data);
        logs.push({
          name: filter.name,
          time: Date.now() - start
        });
      }
      return {
        logs,
        data: result.data
      };
    }

    function getNormalizedSpectrum(spectrum, options = {}) {
      const data = {
        x: spectrum.variables.x.data,
        y: spectrum.variables.y.data
      };
      const newSpectrum = {
        variables: {
          x: {
            data: spectrum.variables.x.data,
            units: spectrum.variables.x.units,
            label: spectrum.variables.x.label
          },
          y: {
            data: spectrum.variables.y.data,
            units: spectrum.variables.y.units,
            label: spectrum.variables.y.label
          }
        }
      };
      if (spectrum.title) newSpectrum.title = spectrum.title;
      if (spectrum.dataType) newSpectrum.dataType = spectrum.dataType;
      if (spectrum.meta) newSpectrum.meta = spectrum.meta;
      if (spectrum.id) newSpectrum.id = spectrum.id;
      const {
        from = spectrum.variables.x.min,
        to = spectrum.variables.x.max,
        numberOfPoints,
        applyRangeSelectionFirst = false,
        exclusions = [],
        zones = []
      } = options;
      let {
        filters = []
      } = options;
      filters = structuredClone(filters);
      if (numberOfPoints) {
        if (applyRangeSelectionFirst) {
          filters.unshift({
            name: 'equallySpaced',
            options: {
              from,
              to,
              exclusions,
              zones,
              numberOfPoints
            }
          });
        } else {
          filters.push({
            name: 'equallySpaced',
            options: {
              from,
              to,
              exclusions,
              zones,
              numberOfPoints
            }
          });
        }
      } else if (applyRangeSelectionFirst) {
        filters.unshift({
          name: 'filterX',
          options: {
            from,
            to,
            exclusions,
            zones
          }
        });
      } else {
        filters.push({
          name: 'filterX',
          options: {
            from,
            to,
            exclusions,
            zones
          }
        });
      }
      const {
        x,
        y
      } = filterXY(data, filters).data;
      // filters change the y axis, we get rid of the units
      // TODO we should deal correctly with this problem
      if (filters.length > 1) {
        newSpectrum.variables.y.units = '';
        newSpectrum.variables.y.label = newSpectrum.variables.y.label?.replace(/\s*\[.*]/, '');
      }
      newSpectrum.variables.x.data = x;
      newSpectrum.variables.x.min = xMinValue(x);
      newSpectrum.variables.x.max = xMaxValue(x);
      newSpectrum.variables.x.isMonotonic = xIsMonotonic(x);
      newSpectrum.variables.y.data = y;
      newSpectrum.variables.y.min = xMinValue(y);
      newSpectrum.variables.y.max = xMaxValue(y);
      newSpectrum.variables.y.isMonotonic = xIsMonotonic(y);
      return newSpectrum;
    }

    var quantities$1 = {exports: {}};

    /*
    The MIT License (MIT)
    Copyright © 2006-2007 Kevin C. Olbrich
    Copyright © 2010-2016 LIM SAS (http://lim.eu) - Julien Sanchez

    Permission is hereby granted, free of charge, to any person obtaining a copy of
    this software and associated documentation files (the "Software"), to deal in
    the Software without restriction, including without limitation the rights to
    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
    of the Software, and to permit persons to whom the Software is furnished to do
    so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    */
    var quantities = quantities$1.exports;
    (function (module, exports$1) {
      (function (global, factory) {
        module.exports = factory() ;
      })(quantities, function () {

        /**
         * Tests if a value is a string
         *
         * @param {*} value - Value to test
         *
         * @returns {boolean} true if value is a string, false otherwise
         */
        function isString(value) {
          return typeof value === "string" || value instanceof String;
        }

        /*
         * Prefer stricter Number.isFinite if currently supported.
         * To be dropped when ES6 is finalized. Obsolete browsers will
         * have to use ES6 polyfills.
         */
        var isFiniteImpl = Number.isFinite || window.isFinite;
        /**
         * Tests if a value is a number
         *
         * @param {*} value - Value to test
         *
         * @returns {boolean} true if value is a number, false otherwise
         */
        function isNumber(value) {
          // Number.isFinite allows not to consider NaN or '1' as numbers
          return isFiniteImpl(value);
        }

        /*
         * Identity function
         */
        function identity(value) {
          return value;
        }

        /**
         * Returns unique strings from list
         *
         * @param {string[]} strings - array of strings
         *
         *
         * @returns {string[]} a new array of strings without duplicates
         */
        function uniq(strings) {
          var seen = {};
          return strings.filter(function (item) {
            return seen.hasOwnProperty(item) ? false : seen[item] = true;
          });
        }
        function compareArray(array1, array2) {
          if (array2.length !== array1.length) {
            return false;
          }
          for (var i = 0; i < array1.length; i++) {
            if (array2[i].compareArray) {
              if (!array2[i].compareArray(array1[i])) {
                return false;
              }
            }
            if (array2[i] !== array1[i]) {
              return false;
            }
          }
          return true;
        }
        function assign(target, properties) {
          Object.keys(properties).forEach(function (key) {
            target[key] = properties[key];
          });
        }

        /**
         * Safely multiplies numbers while avoiding floating errors
         * like 0.1 * 0.1 => 0.010000000000000002
         *
         * @param {...number} numbers - numbers to multiply
         *
         * @returns {number} result
         */
        function mulSafe() {
          var result = 1,
            decimals = 0;
          for (var i = 0; i < arguments.length; i++) {
            var arg = arguments[i];
            decimals = decimals + getFractional(arg);
            result *= arg;
          }
          return decimals !== 0 ? round(result, decimals) : result;
        }

        /**
         * Safely divides two numbers while avoiding floating errors
         * like 0.3 / 0.05 => 5.999999999999999
         *
         * @returns {number} result
         * @param {number} num Numerator
         * @param {number} den Denominator
         */
        function divSafe(num, den) {
          if (den === 0) {
            throw new Error("Divide by zero");
          }
          var factor = Math.pow(10, getFractional(den));
          var invDen = factor / (factor * den);
          return mulSafe(num, invDen);
        }

        /**
         * Rounds value at the specified number of decimals
         *
         * @param {number} val - value to round
         * @param {number} decimals - number of decimals
         *
         * @returns {number} rounded number
         */
        function round(val, decimals) {
          return Math.round(val * Math.pow(10, decimals)) / Math.pow(10, decimals);
        }
        function getFractional(num) {
          // Check for NaNs or Infinities
          if (!isFinite(num)) {
            return 0;
          }

          // Faster than parsing strings
          // http://jsperf.com/count-decimals/2
          var count = 0;
          while (num % 1 !== 0) {
            num *= 10;
            count++;
          }
          return count;
        }

        /**
         * Custom error type definition
         * @constructor
         */
        function QtyError() {
          var err;
          if (!this) {
            // Allows to instantiate QtyError without new()
            err = Object.create(QtyError.prototype);
            QtyError.apply(err, arguments);
            return err;
          }
          err = Error.apply(this, arguments);
          this.name = "QtyError";
          this.message = err.message;
          this.stack = err.stack;
        }
        QtyError.prototype = Object.create(Error.prototype, {
          constructor: {
            value: QtyError
          }
        });

        /*
         * Throws incompatible units error
         * @param {string} left - units
         * @param {string} right - units incompatible with first argument
         * @throws "Incompatible units" error
         */
        function throwIncompatibleUnits(left, right) {
          throw new QtyError("Incompatible units: " + left + " and " + right);
        }
        var UNITS = {
          /* prefixes */
          "<googol>": [["googol"], 1e100, "prefix"],
          "<kibi>": [["Ki", "Kibi", "kibi"], Math.pow(2, 10), "prefix"],
          "<mebi>": [["Mi", "Mebi", "mebi"], Math.pow(2, 20), "prefix"],
          "<gibi>": [["Gi", "Gibi", "gibi"], Math.pow(2, 30), "prefix"],
          "<tebi>": [["Ti", "Tebi", "tebi"], Math.pow(2, 40), "prefix"],
          "<pebi>": [["Pi", "Pebi", "pebi"], Math.pow(2, 50), "prefix"],
          "<exi>": [["Ei", "Exi", "exi"], Math.pow(2, 60), "prefix"],
          "<zebi>": [["Zi", "Zebi", "zebi"], Math.pow(2, 70), "prefix"],
          "<yebi>": [["Yi", "Yebi", "yebi"], Math.pow(2, 80), "prefix"],
          "<yotta>": [["Y", "Yotta", "yotta"], 1e24, "prefix"],
          "<zetta>": [["Z", "Zetta", "zetta"], 1e21, "prefix"],
          "<exa>": [["E", "Exa", "exa"], 1e18, "prefix"],
          "<peta>": [["P", "Peta", "peta"], 1e15, "prefix"],
          "<tera>": [["T", "Tera", "tera"], 1e12, "prefix"],
          "<giga>": [["G", "Giga", "giga"], 1e9, "prefix"],
          "<mega>": [["M", "Mega", "mega"], 1e6, "prefix"],
          "<kilo>": [["k", "kilo"], 1e3, "prefix"],
          "<hecto>": [["h", "Hecto", "hecto"], 1e2, "prefix"],
          "<deca>": [["da", "Deca", "deca", "deka"], 1e1, "prefix"],
          "<deci>": [["d", "Deci", "deci"], 1e-1, "prefix"],
          "<centi>": [["c", "Centi", "centi"], 1e-2, "prefix"],
          "<milli>": [["m", "Milli", "milli"], 1e-3, "prefix"],
          "<micro>": [["u", "\u03BC" /*µ as greek letter*/, "\u00B5" /*µ as micro sign*/, "Micro", "mc", "micro"], 1e-6, "prefix"],
          "<nano>": [["n", "Nano", "nano"], 1e-9, "prefix"],
          "<pico>": [["p", "Pico", "pico"], 1e-12, "prefix"],
          "<femto>": [["f", "Femto", "femto"], 1e-15, "prefix"],
          "<atto>": [["a", "Atto", "atto"], 1e-18, "prefix"],
          "<zepto>": [["z", "Zepto", "zepto"], 1e-21, "prefix"],
          "<yocto>": [["y", "Yocto", "yocto"], 1e-24, "prefix"],
          "<1>": [["1", "<1>"], 1, ""],
          /* length units */
          "<meter>": [["m", "meter", "meters", "metre", "metres"], 1.0, "length", ["<meter>"]],
          "<inch>": [["in", "inch", "inches", "\""], 0.0254, "length", ["<meter>"]],
          "<foot>": [["ft", "foot", "feet", "'"], 0.3048, "length", ["<meter>"]],
          "<yard>": [["yd", "yard", "yards"], 0.9144, "length", ["<meter>"]],
          "<mile>": [["mi", "mile", "miles"], 1609.344, "length", ["<meter>"]],
          "<naut-mile>": [["nmi", "naut-mile"], 1852, "length", ["<meter>"]],
          "<league>": [["league", "leagues"], 4828, "length", ["<meter>"]],
          "<furlong>": [["furlong", "furlongs"], 201.2, "length", ["<meter>"]],
          "<rod>": [["rd", "rod", "rods"], 5.029, "length", ["<meter>"]],
          "<mil>": [["mil", "mils"], 0.0000254, "length", ["<meter>"]],
          "<angstrom>": [["ang", "angstrom", "angstroms"], 1e-10, "length", ["<meter>"]],
          "<fathom>": [["fathom", "fathoms"], 1.829, "length", ["<meter>"]],
          "<pica>": [["pica", "picas"], 0.00423333333, "length", ["<meter>"]],
          "<point>": [["pt", "point", "points"], 0.000352777778, "length", ["<meter>"]],
          "<redshift>": [["z", "red-shift", "redshift"], 1.302773e26, "length", ["<meter>"]],
          "<AU>": [["AU", "astronomical-unit"], 149597900000, "length", ["<meter>"]],
          "<light-second>": [["ls", "light-second"], 299792500, "length", ["<meter>"]],
          "<light-minute>": [["lmin", "light-minute"], 17987550000, "length", ["<meter>"]],
          "<light-year>": [["ly", "light-year"], 9460528000000000, "length", ["<meter>"]],
          "<parsec>": [["pc", "parsec", "parsecs"], 30856780000000000, "length", ["<meter>"]],
          "<datamile>": [["DM", "datamile"], 1828.8, "length", ["<meter>"]],
          /* mass */
          "<kilogram>": [["kg", "kilogram", "kilograms"], 1.0, "mass", ["<kilogram>"]],
          "<AMU>": [["u", "AMU", "amu"], 1.660538921e-27, "mass", ["<kilogram>"]],
          "<dalton>": [["Da", "Dalton", "Daltons", "dalton", "daltons"], 1.660538921e-27, "mass", ["<kilogram>"]],
          "<slug>": [["slug", "slugs"], 14.5939029, "mass", ["<kilogram>"]],
          "<short-ton>": [["tn", "ton", "short-ton"], 907.18474, "mass", ["<kilogram>"]],
          "<metric-ton>": [["t", "tonne", "metric-ton"], 1000, "mass", ["<kilogram>"]],
          "<carat>": [["ct", "carat", "carats"], 0.0002, "mass", ["<kilogram>"]],
          "<pound>": [["lbs", "lb", "pound", "pounds", "#"], 0.45359237, "mass", ["<kilogram>"]],
          "<ounce>": [["oz", "ounce", "ounces"], 0.0283495231, "mass", ["<kilogram>"]],
          "<gram>": [["g", "gram", "grams", "gramme", "grammes"], 1e-3, "mass", ["<kilogram>"]],
          "<grain>": [["grain", "grains", "gr"], 6.479891e-5, "mass", ["<kilogram>"]],
          "<dram>": [["dram", "drams", "dr"], 0.0017718452, "mass", ["<kilogram>"]],
          "<stone>": [["stone", "stones", "st"], 6.35029318, "mass", ["<kilogram>"]],
          /* area */
          "<hectare>": [["hectare"], 10000, "area", ["<meter>", "<meter>"]],
          "<acre>": [["acre", "acres"], 4046.85642, "area", ["<meter>", "<meter>"]],
          "<sqft>": [["sqft"], 1, "area", ["<foot>", "<foot>"]],
          /* volume */
          "<liter>": [["l", "L", "liter", "liters", "litre", "litres"], 0.001, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<gallon>": [["gal", "gallon", "gallons"], 0.0037854118, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<gallon-imp>": [["galimp", "gallon-imp", "gallons-imp"], 0.0045460900, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<quart>": [["qt", "quart", "quarts"], 0.00094635295, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<pint>": [["pt", "pint", "pints"], 0.000473176475, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<pint-imp>": [["ptimp", "pint-imp", "pints-imp"], 5.6826125e-4, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<cup>": [["cu", "cup", "cups"], 0.000236588238, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<fluid-ounce>": [["floz", "fluid-ounce", "fluid-ounces"], 2.95735297e-5, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<fluid-ounce-imp>": [["flozimp", "floz-imp", "fluid-ounce-imp", "fluid-ounces-imp"], 2.84130625e-5, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<tablespoon>": [["tb", "tbsp", "tbs", "tablespoon", "tablespoons"], 1.47867648e-5, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<teaspoon>": [["tsp", "teaspoon", "teaspoons"], 4.92892161e-6, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<bushel>": [["bu", "bsh", "bushel", "bushels"], 0.035239072, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<oilbarrel>": [["bbl", "oilbarrel", "oilbarrels", "oil-barrel", "oil-barrels"], 0.158987294928, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<beerbarrel>": [["bl", "bl-us", "beerbarrel", "beerbarrels", "beer-barrel", "beer-barrels"], 0.1173477658, "volume", ["<meter>", "<meter>", "<meter>"]],
          "<beerbarrel-imp>": [["blimp", "bl-imp", "beerbarrel-imp", "beerbarrels-imp", "beer-barrel-imp", "beer-barrels-imp"], 0.16365924, "volume", ["<meter>", "<meter>", "<meter>"]],
          /* speed */
          "<kph>": [["kph"], 0.277777778, "speed", ["<meter>"], ["<second>"]],
          "<mph>": [["mph"], 0.44704, "speed", ["<meter>"], ["<second>"]],
          "<knot>": [["kt", "kn", "kts", "knot", "knots"], 0.514444444, "speed", ["<meter>"], ["<second>"]],
          "<fps>": [["fps"], 0.3048, "speed", ["<meter>"], ["<second>"]],
          /* acceleration */
          "<gee>": [["gee"], 9.80665, "acceleration", ["<meter>"], ["<second>", "<second>"]],
          "<Gal>": [["Gal"], 1e-2, "acceleration", ["<meter>"], ["<second>", "<second>"]],
          /* temperature_difference */
          "<kelvin>": [["degK", "kelvin"], 1.0, "temperature", ["<kelvin>"]],
          "<celsius>": [["degC", "celsius", "celsius", "centigrade"], 1.0, "temperature", ["<kelvin>"]],
          "<fahrenheit>": [["degF", "fahrenheit"], 5 / 9, "temperature", ["<kelvin>"]],
          "<rankine>": [["degR", "rankine"], 5 / 9, "temperature", ["<kelvin>"]],
          "<temp-K>": [["tempK", "temp-K"], 1.0, "temperature", ["<temp-K>"]],
          "<temp-C>": [["tempC", "temp-C"], 1.0, "temperature", ["<temp-K>"]],
          "<temp-F>": [["tempF", "temp-F"], 5 / 9, "temperature", ["<temp-K>"]],
          "<temp-R>": [["tempR", "temp-R"], 5 / 9, "temperature", ["<temp-K>"]],
          /* time */
          "<second>": [["s", "sec", "secs", "second", "seconds"], 1.0, "time", ["<second>"]],
          "<minute>": [["min", "mins", "minute", "minutes"], 60.0, "time", ["<second>"]],
          "<hour>": [["h", "hr", "hrs", "hour", "hours"], 3600.0, "time", ["<second>"]],
          "<day>": [["d", "day", "days"], 3600 * 24, "time", ["<second>"]],
          "<week>": [["wk", "week", "weeks"], 7 * 3600 * 24, "time", ["<second>"]],
          "<fortnight>": [["fortnight", "fortnights"], 1209600, "time", ["<second>"]],
          "<year>": [["y", "yr", "year", "years", "annum"], 31556926, "time", ["<second>"]],
          "<decade>": [["decade", "decades"], 315569260, "time", ["<second>"]],
          "<century>": [["century", "centuries"], 3155692600, "time", ["<second>"]],
          /* pressure */
          "<pascal>": [["Pa", "pascal", "Pascal"], 1.0, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          "<bar>": [["bar", "bars"], 100000, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          "<mmHg>": [["mmHg"], 133.322368, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          "<inHg>": [["inHg"], 3386.3881472, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          "<torr>": [["torr"], 133.322368, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          "<atm>": [["atm", "ATM", "atmosphere", "atmospheres"], 101325, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          "<psi>": [["psi"], 6894.76, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          "<cmh2o>": [["cmH2O", "cmh2o"], 98.0638, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          "<inh2o>": [["inH2O", "inh2o"], 249.082052, "pressure", ["<kilogram>"], ["<meter>", "<second>", "<second>"]],
          /* viscosity */
          "<poise>": [["P", "poise"], 0.1, "viscosity", ["<kilogram>"], ["<meter>", "<second>"]],
          "<stokes>": [["St", "stokes"], 1e-4, "viscosity", ["<meter>", "<meter>"], ["<second>"]],
          /* substance */
          "<mole>": [["mol", "mole"], 1.0, "substance", ["<mole>"]],
          /* molar_concentration */
          "<molar>": [["M", "molar"], 1000, "molar_concentration", ["<mole>"], ["<meter>", "<meter>", "<meter>"]],
          "<wtpercent>": [["wt%", "wtpercent"], 10, "molar_concentration", ["<kilogram>"], ["<meter>", "<meter>", "<meter>"]],
          /* activity */
          "<katal>": [["kat", "katal", "Katal"], 1.0, "activity", ["<mole>"], ["<second>"]],
          "<unit>": [["U", "enzUnit", "unit"], 16.667e-16, "activity", ["<mole>"], ["<second>"]],
          /* capacitance */
          "<farad>": [["F", "farad", "Farad"], 1.0, "capacitance", ["<second>", "<second>", "<second>", "<second>", "<ampere>", "<ampere>"], ["<meter>", "<meter>", "<kilogram>"]],
          /* charge */
          "<coulomb>": [["C", "coulomb", "Coulomb"], 1.0, "charge", ["<ampere>", "<second>"]],
          "<Ah>": [["Ah"], 3600, "charge", ["<ampere>", "<second>"]],
          /* current */
          "<ampere>": [["A", "Ampere", "ampere", "amp", "amps"], 1.0, "current", ["<ampere>"]],
          /* conductance */
          "<siemens>": [["S", "Siemens", "siemens"], 1.0, "conductance", ["<second>", "<second>", "<second>", "<ampere>", "<ampere>"], ["<kilogram>", "<meter>", "<meter>"]],
          /* inductance */
          "<henry>": [["H", "Henry", "henry"], 1.0, "inductance", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>", "<ampere>", "<ampere>"]],
          /* potential */
          "<volt>": [["V", "Volt", "volt", "volts"], 1.0, "potential", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>", "<second>", "<ampere>"]],
          /* resistance */
          "<ohm>": [["Ohm", "ohm", "\u03A9" /*Ω as greek letter*/, "\u2126" /*Ω as ohm sign*/], 1.0, "resistance", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>", "<second>", "<ampere>", "<ampere>"]],
          /* magnetism */
          "<weber>": [["Wb", "weber", "webers"], 1.0, "magnetism", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>", "<ampere>"]],
          "<tesla>": [["T", "tesla", "teslas"], 1.0, "magnetism", ["<kilogram>"], ["<second>", "<second>", "<ampere>"]],
          "<gauss>": [["G", "gauss"], 1e-4, "magnetism", ["<kilogram>"], ["<second>", "<second>", "<ampere>"]],
          "<maxwell>": [["Mx", "maxwell", "maxwells"], 1e-8, "magnetism", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>", "<ampere>"]],
          "<oersted>": [["Oe", "oersted", "oersteds"], 250.0 / Math.PI, "magnetism", ["<ampere>"], ["<meter>"]],
          /* energy */
          "<joule>": [["J", "joule", "Joule", "joules", "Joules"], 1.0, "energy", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>"]],
          "<erg>": [["erg", "ergs"], 1e-7, "energy", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>"]],
          "<btu>": [["BTU", "btu", "BTUs"], 1055.056, "energy", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>"]],
          "<calorie>": [["cal", "calorie", "calories"], 4.18400, "energy", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>"]],
          "<Calorie>": [["Cal", "Calorie", "Calories"], 4184.00, "energy", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>"]],
          "<therm-US>": [["th", "therm", "therms", "Therm", "therm-US"], 105480400, "energy", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>"]],
          "<Wh>": [["Wh"], 3600, "energy", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>"]],
          "<electronvolt>": [["eV", "electronvolt", "electronvolts"], 1.602176634E-19, "energy", ["<meter>", "<meter>", "<kilogram>"], ["<second>", "<second>"]],
          /* force */
          "<newton>": [["N", "Newton", "newton"], 1.0, "force", ["<kilogram>", "<meter>"], ["<second>", "<second>"]],
          "<dyne>": [["dyn", "dyne"], 1e-5, "force", ["<kilogram>", "<meter>"], ["<second>", "<second>"]],
          "<pound-force>": [["lbf", "pound-force"], 4.448222, "force", ["<kilogram>", "<meter>"], ["<second>", "<second>"]],
          /* frequency */
          "<hertz>": [["Hz", "hertz", "Hertz"], 1.0, "frequency", ["<1>"], ["<second>"]],
          /* angle */
          "<radian>": [["rad", "radian", "radians"], 1.0, "angle", ["<radian>"]],
          "<degree>": [["deg", "degree", "degrees"], Math.PI / 180.0, "angle", ["<radian>"]],
          "<arcminute>": [["arcmin", "arcminute", "arcminutes"], Math.PI / 10800.0, "angle", ["<radian>"]],
          "<arcsecond>": [["arcsec", "arcsecond", "arcseconds"], Math.PI / 648000.0, "angle", ["<radian>"]],
          "<gradian>": [["gon", "grad", "gradian", "grads"], Math.PI / 200.0, "angle", ["<radian>"]],
          "<steradian>": [["sr", "steradian", "steradians"], 1.0, "solid_angle", ["<steradian>"]],
          /* rotation */
          "<rotation>": [["rotation"], 2.0 * Math.PI, "angle", ["<radian>"]],
          "<rpm>": [["rpm"], 2.0 * Math.PI / 60.0, "angular_velocity", ["<radian>"], ["<second>"]],
          /* information */
          "<byte>": [["B", "byte", "bytes"], 1.0, "information", ["<byte>"]],
          "<bit>": [["b", "bit", "bits"], 0.125, "information", ["<byte>"]],
          /* information rate */
          "<Bps>": [["Bps"], 1.0, "information_rate", ["<byte>"], ["<second>"]],
          "<bps>": [["bps"], 0.125, "information_rate", ["<byte>"], ["<second>"]],
          /* currency */
          "<dollar>": [["USD", "dollar"], 1.0, "currency", ["<dollar>"]],
          "<cents>": [["cents"], 0.01, "currency", ["<dollar>"]],
          /* luminosity */
          "<candela>": [["cd", "candela"], 1.0, "luminosity", ["<candela>"]],
          "<lumen>": [["lm", "lumen"], 1.0, "luminous_power", ["<candela>", "<steradian>"]],
          "<lux>": [["lux"], 1.0, "illuminance", ["<candela>", "<steradian>"], ["<meter>", "<meter>"]],
          /* power */
          "<watt>": [["W", "watt", "watts"], 1.0, "power", ["<kilogram>", "<meter>", "<meter>"], ["<second>", "<second>", "<second>"]],
          "<volt-ampere>": [["VA", "volt-ampere"], 1.0, "power", ["<kilogram>", "<meter>", "<meter>"], ["<second>", "<second>", "<second>"]],
          "<volt-ampere-reactive>": [["var", "Var", "VAr", "VAR", "volt-ampere-reactive"], 1.0, "power", ["<kilogram>", "<meter>", "<meter>"], ["<second>", "<second>", "<second>"]],
          "<horsepower>": [["hp", "horsepower"], 745.699872, "power", ["<kilogram>", "<meter>", "<meter>"], ["<second>", "<second>", "<second>"]],
          /* radiation */
          "<gray>": [["Gy", "gray", "grays"], 1.0, "radiation", ["<meter>", "<meter>"], ["<second>", "<second>"]],
          "<roentgen>": [["R", "roentgen"], 0.009330, "radiation", ["<meter>", "<meter>"], ["<second>", "<second>"]],
          "<sievert>": [["Sv", "sievert", "sieverts"], 1.0, "radiation", ["<meter>", "<meter>"], ["<second>", "<second>"]],
          "<becquerel>": [["Bq", "becquerel", "becquerels"], 1.0, "radiation", ["<1>"], ["<second>"]],
          "<curie>": [["Ci", "curie", "curies"], 3.7e10, "radiation", ["<1>"], ["<second>"]],
          /* rate */
          "<cpm>": [["cpm"], 1.0 / 60.0, "rate", ["<count>"], ["<second>"]],
          "<dpm>": [["dpm"], 1.0 / 60.0, "rate", ["<count>"], ["<second>"]],
          "<bpm>": [["bpm"], 1.0 / 60.0, "rate", ["<count>"], ["<second>"]],
          /* resolution / typography */
          "<dot>": [["dot", "dots"], 1, "resolution", ["<each>"]],
          "<pixel>": [["pixel", "px"], 1, "resolution", ["<each>"]],
          "<ppi>": [["ppi"], 1, "resolution", ["<pixel>"], ["<inch>"]],
          "<dpi>": [["dpi"], 1, "typography", ["<dot>"], ["<inch>"]],
          /* other */
          "<cell>": [["cells", "cell"], 1, "counting", ["<each>"]],
          "<each>": [["each"], 1.0, "counting", ["<each>"]],
          "<count>": [["count"], 1.0, "counting", ["<each>"]],
          "<base-pair>": [["bp", "base-pair"], 1.0, "counting", ["<each>"]],
          "<nucleotide>": [["nt", "nucleotide"], 1.0, "counting", ["<each>"]],
          "<molecule>": [["molecule", "molecules"], 1.0, "counting", ["<1>"]],
          "<dozen>": [["doz", "dz", "dozen"], 12.0, "prefix_only", ["<each>"]],
          "<percent>": [["%", "percent"], 0.01, "prefix_only", ["<1>"]],
          "<ppm>": [["ppm"], 1e-6, "prefix_only", ["<1>"]],
          "<ppb>": [["ppb"], 1e-9, "prefix_only", ["<1>"]],
          "<ppt>": [["ppt"], 1e-12, "prefix_only", ["<1>"]],
          "<ppq>": [["ppq"], 1e-15, "prefix_only", ["<1>"]],
          "<gross>": [["gr", "gross"], 144.0, "prefix_only", ["<dozen>", "<dozen>"]],
          "<decibel>": [["dB", "decibel", "decibels"], 1.0, "logarithmic", ["<decibel>"]]
        };
        var BASE_UNITS = ["<meter>", "<kilogram>", "<second>", "<mole>", "<ampere>", "<radian>", "<kelvin>", "<temp-K>", "<byte>", "<dollar>", "<candela>", "<each>", "<steradian>", "<decibel>"];
        var UNITY = "<1>";
        var UNITY_ARRAY = [UNITY];

        // Setup

        /**
         * Asserts unit definition is valid
         *
         * @param {string} unitDef - Name of unit to test
         * @param {Object} definition - Definition of unit to test
         *
         * @returns {void}
         * @throws {QtyError} if unit definition is not valid
         */
        function validateUnitDefinition(unitDef, definition) {
          var scalar = definition[1];
          var numerator = definition[3] || [];
          var denominator = definition[4] || [];
          if (!isNumber(scalar)) {
            throw new QtyError(unitDef + ": Invalid unit definition. " + "'scalar' must be a number");
          }
          numerator.forEach(function (unit) {
            if (UNITS[unit] === undefined) {
              throw new QtyError(unitDef + ": Invalid unit definition. " + "Unit " + unit + " in 'numerator' is not recognized");
            }
          });
          denominator.forEach(function (unit) {
            if (UNITS[unit] === undefined) {
              throw new QtyError(unitDef + ": Invalid unit definition. " + "Unit " + unit + " in 'denominator' is not recognized");
            }
          });
        }
        var PREFIX_VALUES = {};
        var PREFIX_MAP = {};
        var UNIT_VALUES = {};
        var UNIT_MAP = {};
        var OUTPUT_MAP = {};
        for (var unitDef in UNITS) {
          if (UNITS.hasOwnProperty(unitDef)) {
            var definition = UNITS[unitDef];
            if (definition[2] === "prefix") {
              PREFIX_VALUES[unitDef] = definition[1];
              for (var i = 0; i < definition[0].length; i++) {
                PREFIX_MAP[definition[0][i]] = unitDef;
              }
            } else {
              validateUnitDefinition(unitDef, definition);
              UNIT_VALUES[unitDef] = {
                scalar: definition[1],
                numerator: definition[3],
                denominator: definition[4]
              };
              for (var j = 0; j < definition[0].length; j++) {
                UNIT_MAP[definition[0][j]] = unitDef;
              }
            }
            OUTPUT_MAP[unitDef] = definition[0][0];
          }
        }

        /**
         * Returns a list of available units of kind
         *
         * @param {string} [kind] - kind of units
         * @returns {array} names of units
         * @throws {QtyError} if kind is unknown
         */
        function getUnits(kind) {
          var i;
          var units = [];
          var unitKeys = Object.keys(UNITS);
          if (typeof kind === "undefined") {
            for (i = 0; i < unitKeys.length; i++) {
              if (["", "prefix"].indexOf(UNITS[unitKeys[i]][2]) === -1) {
                units.push(unitKeys[i].substr(1, unitKeys[i].length - 2));
              }
            }
          } else if (this.getKinds().indexOf(kind) === -1) {
            throw new QtyError("Kind not recognized");
          } else {
            for (i = 0; i < unitKeys.length; i++) {
              if (UNITS[unitKeys[i]][2] === kind) {
                units.push(unitKeys[i].substr(1, unitKeys[i].length - 2));
              }
            }
          }
          return units.sort(function (a, b) {
            if (a.toLowerCase() < b.toLowerCase()) {
              return -1;
            }
            if (a.toLowerCase() > b.toLowerCase()) {
              return 1;
            }
            return 0;
          });
        }

        /**
         * Returns a list of alternative names for a unit
         *
         * @param {string} unitName - name of unit
         * @returns {string[]} aliases for unit
         * @throws {QtyError} if unit is unknown
         */
        function getAliases(unitName) {
          if (!UNIT_MAP[unitName]) {
            throw new QtyError("Unit not recognized");
          }
          return UNITS[UNIT_MAP[unitName]][0];
        }
        var SIGNATURE_VECTOR = ["length", "time", "temperature", "mass", "current", "substance", "luminosity", "currency", "information", "angle"];

        /*
        calculates the unit signature id for use in comparing compatible units and simplification
        the signature is based on a simple classification of units and is based on the following publication
         Novak, G.S., Jr. "Conversion of units of measurement", IEEE Transactions on Software Engineering,
        21(8), Aug 1995, pp.651-661
        doi://10.1109/32.403789
        http://ieeexplore.ieee.org/Xplore/login.jsp?url=/iel1/32/9079/00403789.pdf?isnumber=9079&prod=JNL&arnumber=403789&arSt=651&ared=661&arAuthor=Novak%2C+G.S.%2C+Jr.
        */
        function unitSignature() {
          if (this.signature) {
            return this.signature;
          }
          var vector = unitSignatureVector.call(this);
          for (var i = 0; i < vector.length; i++) {
            vector[i] *= Math.pow(20, i);
          }
          return vector.reduce(function (previous, current) {
            return previous + current;
          }, 0);
        }

        // calculates the unit signature vector used by unit_signature
        function unitSignatureVector() {
          if (!this.isBase()) {
            return unitSignatureVector.call(this.toBase());
          }
          var vector = new Array(SIGNATURE_VECTOR.length);
          for (var i = 0; i < vector.length; i++) {
            vector[i] = 0;
          }
          var r, n;
          for (var j = 0; j < this.numerator.length; j++) {
            if (r = UNITS[this.numerator[j]]) {
              n = SIGNATURE_VECTOR.indexOf(r[2]);
              if (n >= 0) {
                vector[n] = vector[n] + 1;
              }
            }
          }
          for (var k = 0; k < this.denominator.length; k++) {
            if (r = UNITS[this.denominator[k]]) {
              n = SIGNATURE_VECTOR.indexOf(r[2]);
              if (n >= 0) {
                vector[n] = vector[n] - 1;
              }
            }
          }
          return vector;
        }
        var SIGN = "[+-]";
        var INTEGER = "\\d+";
        var SIGNED_INTEGER = SIGN + "?" + INTEGER;
        var FRACTION = "\\." + INTEGER;
        var FLOAT = "(?:" + INTEGER + "(?:" + FRACTION + ")?" + ")" + "|" + "(?:" + FRACTION + ")";
        var EXPONENT = "[Ee]" + SIGNED_INTEGER;
        var SCI_NUMBER = "(?:" + FLOAT + ")(?:" + EXPONENT + ")?";
        var SIGNED_NUMBER = SIGN + "?\\s*" + SCI_NUMBER;
        var QTY_STRING = "(" + SIGNED_NUMBER + ")?" + "\\s*([^/]*)(?:\/(.+))?";
        var QTY_STRING_REGEX = new RegExp("^" + QTY_STRING + "$");
        var POWER_OP = "\\^|\\*{2}";
        // Allow unit powers representing scalar, length, area, volume; 4 is for some
        // special case representations in SI base units.
        var SAFE_POWER = "[01234]";
        var TOP_REGEX = new RegExp("([^ \\*\\d]+?)(?:" + POWER_OP + ")?(-?" + SAFE_POWER + "(?![a-zA-Z]))");
        var BOTTOM_REGEX = new RegExp("([^ \\*\\d]+?)(?:" + POWER_OP + ")?(" + SAFE_POWER + "(?![a-zA-Z]))");

        /* parse a string into a unit object.
         * Typical formats like :
         * "5.6 kg*m/s^2"
         * "5.6 kg*m*s^-2"
         * "5.6 kilogram*meter*second^-2"
         * "2.2 kPa"
         * "37 degC"
         * "1"  -- creates a unitless constant with value 1
         * "GPa"  -- creates a unit with scalar 1 with units 'GPa'
         * 6'4"  -- recognized as 6 feet + 4 inches
         * 8 lbs 8 oz -- recognized as 8 lbs + 8 ounces
         */
        function parse(val) {
          if (!isString(val)) {
            val = val.toString();
          }
          val = val.trim();
          var result = QTY_STRING_REGEX.exec(val);
          if (!result) {
            throw new QtyError(val + ": Quantity not recognized");
          }
          var scalarMatch = result[1];
          if (scalarMatch) {
            // Allow whitespaces between sign and scalar for loose parsing
            scalarMatch = scalarMatch.replace(/\s/g, "");
            this.scalar = parseFloat(scalarMatch);
          } else {
            this.scalar = 1;
          }
          var top = result[2];
          var bottom = result[3];
          var n, x, nx;
          // TODO DRY me
          while (result = TOP_REGEX.exec(top)) {
            n = parseFloat(result[2]);
            if (isNaN(n)) {
              // Prevents infinite loops
              throw new QtyError("Unit exponent is not a number");
            }
            // Disallow unrecognized unit even if exponent is 0
            if (n === 0 && !UNIT_TEST_REGEX.test(result[1])) {
              throw new QtyError("Unit not recognized");
            }
            x = result[1] + " ";
            nx = "";
            for (var i = 0; i < Math.abs(n); i++) {
              nx += x;
            }
            if (n >= 0) {
              top = top.replace(result[0], nx);
            } else {
              bottom = bottom ? bottom + nx : nx;
              top = top.replace(result[0], "");
            }
          }
          while (result = BOTTOM_REGEX.exec(bottom)) {
            n = parseFloat(result[2]);
            if (isNaN(n)) {
              // Prevents infinite loops
              throw new QtyError("Unit exponent is not a number");
            }
            // Disallow unrecognized unit even if exponent is 0
            if (n === 0 && !UNIT_TEST_REGEX.test(result[1])) {
              throw new QtyError("Unit not recognized");
            }
            x = result[1] + " ";
            nx = "";
            for (var j = 0; j < n; j++) {
              nx += x;
            }
            bottom = bottom.replace(result[0], nx);
          }
          if (top) {
            this.numerator = parseUnits(top.trim());
          }
          if (bottom) {
            this.denominator = parseUnits(bottom.trim());
          }
        }
        var PREFIX_REGEX = Object.keys(PREFIX_MAP).sort(function (a, b) {
          return b.length - a.length;
        }).join("|");
        var UNIT_REGEX = Object.keys(UNIT_MAP).sort(function (a, b) {
          return b.length - a.length;
        }).join("|");
        /*
         * Minimal boundary regex to support units with Unicode characters
         * \b only works for ASCII
         */
        var BOUNDARY_REGEX = "\\b|$";
        var UNIT_MATCH = "(" + PREFIX_REGEX + ")??(" + UNIT_REGEX + ")(?:" + BOUNDARY_REGEX + ")";
        var UNIT_TEST_REGEX = new RegExp("^\\s*(" + UNIT_MATCH + "[\\s\\*]*)+$");
        var UNIT_MATCH_REGEX = new RegExp(UNIT_MATCH, "g"); // g flag for multiple occurences
        var parsedUnitsCache = {};
        /**
         * Parses and converts units string to normalized unit array.
         * Result is cached to speed up next calls.
         *
         * @param {string} units Units string
         * @returns {string[]} Array of normalized units
         *
         * @example
         * // Returns ["<second>", "<meter>", "<second>"]
         * parseUnits("s m s");
         *
         */
        function parseUnits(units) {
          var cached = parsedUnitsCache[units];
          if (cached) {
            return cached;
          }
          var unitMatch,
            normalizedUnits = [];

          // Scan
          if (!UNIT_TEST_REGEX.test(units)) {
            throw new QtyError("Unit not recognized");
          }
          while (unitMatch = UNIT_MATCH_REGEX.exec(units)) {
            normalizedUnits.push(unitMatch.slice(1));
          }
          normalizedUnits = normalizedUnits.map(function (item) {
            return PREFIX_MAP[item[0]] ? [PREFIX_MAP[item[0]], UNIT_MAP[item[1]]] : [UNIT_MAP[item[1]]];
          });

          // Flatten and remove null elements
          normalizedUnits = normalizedUnits.reduce(function (a, b) {
            return a.concat(b);
          }, []);
          normalizedUnits = normalizedUnits.filter(function (item) {
            return item;
          });
          parsedUnitsCache[units] = normalizedUnits;
          return normalizedUnits;
        }

        /**
         * Parses a string as a quantity
         * @param {string} value - quantity as text
         * @throws if value is not a string
         * @returns {Qty|null} Parsed quantity or null if unrecognized
         */
        function globalParse(value) {
          if (!isString(value)) {
            throw new QtyError("Argument should be a string");
          }
          try {
            return this(value);
          } catch (e) {
            return null;
          }
        }

        /**
         * Tests if a value is a Qty instance
         *
         * @param {*} value - Value to test
         *
         * @returns {boolean} true if value is a Qty instance, false otherwise
         */
        function isQty(value) {
          return value instanceof Qty;
        }
        function Qty(initValue, initUnits) {
          assertValidConstructorArgs.apply(null, arguments);
          if (!isQty(this)) {
            return new Qty(initValue, initUnits);
          }
          this.scalar = null;
          this.baseScalar = null;
          this.signature = null;
          this._conversionCache = {};
          this.numerator = UNITY_ARRAY;
          this.denominator = UNITY_ARRAY;
          if (isDefinitionObject(initValue)) {
            this.scalar = initValue.scalar;
            this.numerator = initValue.numerator && initValue.numerator.length !== 0 ? initValue.numerator : UNITY_ARRAY;
            this.denominator = initValue.denominator && initValue.denominator.length !== 0 ? initValue.denominator : UNITY_ARRAY;
          } else if (initUnits) {
            parse.call(this, initUnits);
            this.scalar = initValue;
          } else {
            parse.call(this, initValue);
          }

          // math with temperatures is very limited
          if (this.denominator.join("*").indexOf("temp") >= 0) {
            throw new QtyError("Cannot divide with temperatures");
          }
          if (this.numerator.join("*").indexOf("temp") >= 0) {
            if (this.numerator.length > 1) {
              throw new QtyError("Cannot multiply by temperatures");
            }
            if (!compareArray(this.denominator, UNITY_ARRAY)) {
              throw new QtyError("Cannot divide with temperatures");
            }
          }
          this.initValue = initValue;
          updateBaseScalar.call(this);
          if (this.isTemperature() && this.baseScalar < 0) {
            throw new QtyError("Temperatures must not be less than absolute zero");
          }
        }
        Qty.prototype = {
          // Properly set up constructor
          constructor: Qty
        };

        /**
         * Asserts constructor arguments are valid
         *
         * @param {*} value - Value to test
         * @param {string} [units] - Optional units when value is passed as a number
         *
         * @returns {void}
         * @throws {QtyError} if constructor arguments are invalid
         */
        function assertValidConstructorArgs(value, units) {
          if (units) {
            if (!(isNumber(value) && isString(units))) {
              throw new QtyError("Only number accepted as initialization value " + "when units are explicitly provided");
            }
          } else {
            if (!(isString(value) || isNumber(value) || isQty(value) || isDefinitionObject(value))) {
              throw new QtyError("Only string, number or quantity accepted as " + "single initialization value");
            }
          }
        }

        /**
         * Tests if a value is a Qty definition object
         *
         * @param {*} value - Value to test
         *
         * @returns {boolean} true if value is a definition object, false otherwise
         */
        function isDefinitionObject(value) {
          return value && typeof value === "object" && value.hasOwnProperty("scalar");
        }
        function updateBaseScalar() {
          if (this.baseScalar) {
            return this.baseScalar;
          }
          if (this.isBase()) {
            this.baseScalar = this.scalar;
            this.signature = unitSignature.call(this);
          } else {
            var base = this.toBase();
            this.baseScalar = base.scalar;
            this.signature = base.signature;
          }
        }
        var KINDS = {
          "-312078": "elastance",
          "-312058": "resistance",
          "-312038": "inductance",
          "-152058": "potential",
          "-152040": "magnetism",
          "-152038": "magnetism",
          "-7997": "specific_volume",
          "-79": "snap",
          "-59": "jolt",
          "-39": "acceleration",
          "-38": "radiation",
          "-20": "frequency",
          "-19": "speed",
          "-18": "viscosity",
          "-17": "volumetric_flow",
          "-1": "wavenumber",
          "0": "unitless",
          "1": "length",
          "2": "area",
          "3": "volume",
          "20": "time",
          "400": "temperature",
          "7941": "yank",
          "7942": "power",
          "7959": "pressure",
          "7961": "force",
          "7962": "energy",
          "7979": "viscosity",
          "7981": "momentum",
          "7982": "angular_momentum",
          "7997": "density",
          "7998": "area_density",
          "8000": "mass",
          "152020": "radiation_exposure",
          "159999": "magnetism",
          "160000": "current",
          "160020": "charge",
          "312058": "conductance",
          "312078": "capacitance",
          "3199980": "activity",
          "3199997": "molar_concentration",
          "3200000": "substance",
          "63999998": "illuminance",
          "64000000": "luminous_power",
          "1280000000": "currency",
          "25599999980": "information_rate",
          "25600000000": "information",
          "511999999980": "angular_velocity",
          "512000000000": "angle"
        };

        /**
         * Returns the list of available well-known kinds of units, e.g.
         * "radiation" or "length".
         *
         * @returns {string[]} names of kinds of units
         */
        function getKinds() {
          return uniq(Object.keys(KINDS).map(function (knownSignature) {
            return KINDS[knownSignature];
          }));
        }
        Qty.prototype.kind = function () {
          return KINDS[this.signature.toString()];
        };
        assign(Qty.prototype, {
          isDegrees: function () {
            // signature may not have been calculated yet
            return (this.signature === null || this.signature === 400) && this.numerator.length === 1 && compareArray(this.denominator, UNITY_ARRAY) && (this.numerator[0].match(/<temp-[CFRK]>/) || this.numerator[0].match(/<(kelvin|celsius|rankine|fahrenheit)>/));
          },
          isTemperature: function () {
            return this.isDegrees() && this.numerator[0].match(/<temp-[CFRK]>/);
          }
        });
        function subtractTemperatures(lhs, rhs) {
          var lhsUnits = lhs.units();
          var rhsConverted = rhs.to(lhsUnits);
          var dstDegrees = Qty(getDegreeUnits(lhsUnits));
          return Qty({
            "scalar": lhs.scalar - rhsConverted.scalar,
            "numerator": dstDegrees.numerator,
            "denominator": dstDegrees.denominator
          });
        }
        function subtractTempDegrees(temp, deg) {
          var tempDegrees = deg.to(getDegreeUnits(temp.units()));
          return Qty({
            "scalar": temp.scalar - tempDegrees.scalar,
            "numerator": temp.numerator,
            "denominator": temp.denominator
          });
        }
        function addTempDegrees(temp, deg) {
          var tempDegrees = deg.to(getDegreeUnits(temp.units()));
          return Qty({
            "scalar": temp.scalar + tempDegrees.scalar,
            "numerator": temp.numerator,
            "denominator": temp.denominator
          });
        }
        function getDegreeUnits(units) {
          if (units === "tempK") {
            return "degK";
          } else if (units === "tempC") {
            return "degC";
          } else if (units === "tempF") {
            return "degF";
          } else if (units === "tempR") {
            return "degR";
          } else {
            throw new QtyError("Unknown type for temp conversion from: " + units);
          }
        }
        function toDegrees(src, dst) {
          var srcDegK = toDegK(src);
          var dstUnits = dst.units();
          var dstScalar;
          if (dstUnits === "degK") {
            dstScalar = srcDegK.scalar;
          } else if (dstUnits === "degC") {
            dstScalar = srcDegK.scalar;
          } else if (dstUnits === "degF") {
            dstScalar = srcDegK.scalar * 9 / 5;
          } else if (dstUnits === "degR") {
            dstScalar = srcDegK.scalar * 9 / 5;
          } else {
            throw new QtyError("Unknown type for degree conversion to: " + dstUnits);
          }
          return Qty({
            "scalar": dstScalar,
            "numerator": dst.numerator,
            "denominator": dst.denominator
          });
        }
        function toDegK(qty) {
          var units = qty.units();
          var q;
          if (units.match(/(deg)[CFRK]/)) {
            q = qty.baseScalar;
          } else if (units === "tempK") {
            q = qty.scalar;
          } else if (units === "tempC") {
            q = qty.scalar;
          } else if (units === "tempF") {
            q = qty.scalar * 5 / 9;
          } else if (units === "tempR") {
            q = qty.scalar * 5 / 9;
          } else {
            throw new QtyError("Unknown type for temp conversion from: " + units);
          }
          return Qty({
            "scalar": q,
            "numerator": ["<kelvin>"],
            "denominator": UNITY_ARRAY
          });
        }
        function toTemp(src, dst) {
          var dstUnits = dst.units();
          var dstScalar;
          if (dstUnits === "tempK") {
            dstScalar = src.baseScalar;
          } else if (dstUnits === "tempC") {
            dstScalar = src.baseScalar - 273.15;
          } else if (dstUnits === "tempF") {
            dstScalar = src.baseScalar * 9 / 5 - 459.67;
          } else if (dstUnits === "tempR") {
            dstScalar = src.baseScalar * 9 / 5;
          } else {
            throw new QtyError("Unknown type for temp conversion to: " + dstUnits);
          }
          return Qty({
            "scalar": dstScalar,
            "numerator": dst.numerator,
            "denominator": dst.denominator
          });
        }
        function toTempK(qty) {
          var units = qty.units();
          var q;
          if (units.match(/(deg)[CFRK]/)) {
            q = qty.baseScalar;
          } else if (units === "tempK") {
            q = qty.scalar;
          } else if (units === "tempC") {
            q = qty.scalar + 273.15;
          } else if (units === "tempF") {
            q = (qty.scalar + 459.67) * 5 / 9;
          } else if (units === "tempR") {
            q = qty.scalar * 5 / 9;
          } else {
            throw new QtyError("Unknown type for temp conversion from: " + units);
          }
          return Qty({
            "scalar": q,
            "numerator": ["<temp-K>"],
            "denominator": UNITY_ARRAY
          });
        }
        assign(Qty.prototype, {
          /**
           * Converts to other compatible units.
           * Instance's converted quantities are cached for faster subsequent calls.
           *
           * @param {(string|Qty)} other - Target units as string or retrieved from
           *                               other Qty instance (scalar is ignored)
           *
           * @returns {Qty} New converted Qty instance with target units
           *
           * @throws {QtyError} if target units are incompatible
           *
           * @example
           * var weight = Qty("25 kg");
           * weight.to("lb"); // => Qty("55.11556554621939 lbs");
           * weight.to(Qty("3 g")); // => Qty("25000 g"); // scalar of passed Qty is ignored
           */
          to: function (other) {
            var cached, target;
            if (other === undefined || other === null) {
              return this;
            }
            if (!isString(other)) {
              return this.to(other.units());
            }
            cached = this._conversionCache[other];
            if (cached) {
              return cached;
            }

            // Instantiating target to normalize units
            target = Qty(other);
            if (target.units() === this.units()) {
              return this;
            }
            if (!this.isCompatible(target)) {
              if (this.isInverse(target)) {
                target = this.inverse().to(other);
              } else {
                throwIncompatibleUnits(this.units(), target.units());
              }
            } else {
              if (target.isTemperature()) {
                target = toTemp(this, target);
              } else if (target.isDegrees()) {
                target = toDegrees(this, target);
              } else {
                var q = divSafe(this.baseScalar, target.baseScalar);
                target = Qty({
                  "scalar": q,
                  "numerator": target.numerator,
                  "denominator": target.denominator
                });
              }
            }
            this._conversionCache[other] = target;
            return target;
          },
          // convert to base SI units
          // results of the conversion are cached so subsequent calls to this will be fast
          toBase: function () {
            if (this.isBase()) {
              return this;
            }
            if (this.isTemperature()) {
              return toTempK(this);
            }
            var cached = baseUnitCache[this.units()];
            if (!cached) {
              cached = toBaseUnits(this.numerator, this.denominator);
              baseUnitCache[this.units()] = cached;
            }
            return cached.mul(this.scalar);
          },
          // Converts the unit back to a float if it is unitless.  Otherwise raises an exception
          toFloat: function () {
            if (this.isUnitless()) {
              return this.scalar;
            }
            throw new QtyError("Can't convert to Float unless unitless.  Use Unit#scalar");
          },
          /**
           * Returns the nearest multiple of quantity passed as
           * precision
           *
           * @param {(Qty|string|number)} precQuantity - Quantity, string formated
           *   quantity or number as expected precision
           *
           * @returns {Qty} Nearest multiple of precQuantity
           *
           * @example
           * Qty('5.5 ft').toPrec('2 ft'); // returns 6 ft
           * Qty('0.8 cu').toPrec('0.25 cu'); // returns 0.75 cu
           * Qty('6.3782 m').toPrec('cm'); // returns 6.38 m
           * Qty('1.146 MPa').toPrec('0.1 bar'); // returns 1.15 MPa
           *
           */
          toPrec: function (precQuantity) {
            if (isString(precQuantity)) {
              precQuantity = Qty(precQuantity);
            }
            if (isNumber(precQuantity)) {
              precQuantity = Qty(precQuantity + " " + this.units());
            }
            if (!this.isUnitless()) {
              precQuantity = precQuantity.to(this.units());
            } else if (!precQuantity.isUnitless()) {
              throwIncompatibleUnits(this.units(), precQuantity.units());
            }
            if (precQuantity.scalar === 0) {
              throw new QtyError("Divide by zero");
            }
            var precRoundedResult = mulSafe(Math.round(this.scalar / precQuantity.scalar), precQuantity.scalar);
            return Qty(precRoundedResult + this.units());
          }
        });

        /**
         * Configures and returns a fast function to convert
         * Number values from units to others.
         * Useful to efficiently convert large array of values
         * with same units into others with iterative methods.
         * Does not take care of rounding issues.
         *
         * @param {string} srcUnits Units of values to convert
         * @param {string} dstUnits Units to convert to
         *
         * @returns {Function} Converting function accepting Number value
         *   and returning converted value
         *
         * @throws "Incompatible units" if units are incompatible
         *
         * @example
         * // Converting large array of numbers with the same units
         * // into other units
         * var converter = Qty.swiftConverter("m/h", "ft/s");
         * var convertedSerie = largeSerie.map(converter);
         *
         */
        function swiftConverter(srcUnits, dstUnits) {
          var srcQty = Qty(srcUnits);
          var dstQty = Qty(dstUnits);
          if (srcQty.eq(dstQty)) {
            return identity;
          }
          var convert;
          if (!srcQty.isTemperature()) {
            convert = function (value) {
              return value * srcQty.baseScalar / dstQty.baseScalar;
            };
          } else {
            convert = function (value) {
              // TODO Not optimized
              return srcQty.mul(value).to(dstQty).scalar;
            };
          }
          return function converter(value) {
            var i, length, result;
            if (!Array.isArray(value)) {
              return convert(value);
            } else {
              length = value.length;
              result = [];
              for (i = 0; i < length; i++) {
                result.push(convert(value[i]));
              }
              return result;
            }
          };
        }
        var baseUnitCache = {};
        function toBaseUnits(numerator, denominator) {
          var num = [];
          var den = [];
          var q = 1;
          var unit;
          for (var i = 0; i < numerator.length; i++) {
            unit = numerator[i];
            if (PREFIX_VALUES[unit]) {
              // workaround to fix
              // 0.1 * 0.1 => 0.010000000000000002
              q = mulSafe(q, PREFIX_VALUES[unit]);
            } else {
              if (UNIT_VALUES[unit]) {
                q *= UNIT_VALUES[unit].scalar;
                if (UNIT_VALUES[unit].numerator) {
                  num.push(UNIT_VALUES[unit].numerator);
                }
                if (UNIT_VALUES[unit].denominator) {
                  den.push(UNIT_VALUES[unit].denominator);
                }
              }
            }
          }
          for (var j = 0; j < denominator.length; j++) {
            unit = denominator[j];
            if (PREFIX_VALUES[unit]) {
              q /= PREFIX_VALUES[unit];
            } else {
              if (UNIT_VALUES[unit]) {
                q /= UNIT_VALUES[unit].scalar;
                if (UNIT_VALUES[unit].numerator) {
                  den.push(UNIT_VALUES[unit].numerator);
                }
                if (UNIT_VALUES[unit].denominator) {
                  num.push(UNIT_VALUES[unit].denominator);
                }
              }
            }
          }

          // Flatten
          num = num.reduce(function (a, b) {
            return a.concat(b);
          }, []);
          den = den.reduce(function (a, b) {
            return a.concat(b);
          }, []);
          return Qty({
            "scalar": q,
            "numerator": num,
            "denominator": den
          });
        }
        Qty.parse = globalParse;
        Qty.getUnits = getUnits;
        Qty.getAliases = getAliases;
        Qty.mulSafe = mulSafe;
        Qty.divSafe = divSafe;
        Qty.getKinds = getKinds;
        Qty.swiftConverter = swiftConverter;
        Qty.Error = QtyError;
        assign(Qty.prototype, {
          // Returns new instance with units of this
          add: function (other) {
            if (isString(other)) {
              other = Qty(other);
            }
            if (!this.isCompatible(other)) {
              throwIncompatibleUnits(this.units(), other.units());
            }
            if (this.isTemperature() && other.isTemperature()) {
              throw new QtyError("Cannot add two temperatures");
            } else if (this.isTemperature()) {
              return addTempDegrees(this, other);
            } else if (other.isTemperature()) {
              return addTempDegrees(other, this);
            }
            return Qty({
              "scalar": this.scalar + other.to(this).scalar,
              "numerator": this.numerator,
              "denominator": this.denominator
            });
          },
          sub: function (other) {
            if (isString(other)) {
              other = Qty(other);
            }
            if (!this.isCompatible(other)) {
              throwIncompatibleUnits(this.units(), other.units());
            }
            if (this.isTemperature() && other.isTemperature()) {
              return subtractTemperatures(this, other);
            } else if (this.isTemperature()) {
              return subtractTempDegrees(this, other);
            } else if (other.isTemperature()) {
              throw new QtyError("Cannot subtract a temperature from a differential degree unit");
            }
            return Qty({
              "scalar": this.scalar - other.to(this).scalar,
              "numerator": this.numerator,
              "denominator": this.denominator
            });
          },
          mul: function (other) {
            if (isNumber(other)) {
              return Qty({
                "scalar": mulSafe(this.scalar, other),
                "numerator": this.numerator,
                "denominator": this.denominator
              });
            } else if (isString(other)) {
              other = Qty(other);
            }
            if ((this.isTemperature() || other.isTemperature()) && !(this.isUnitless() || other.isUnitless())) {
              throw new QtyError("Cannot multiply by temperatures");
            }

            // Quantities should be multiplied with same units if compatible, with base units else
            var op1 = this;
            var op2 = other;

            // so as not to confuse results, multiplication and division between temperature degrees will maintain original unit info in num/den
            // multiplication and division between deg[CFRK] can never factor each other out, only themselves: "degK*degC/degC^2" == "degK/degC"
            if (op1.isCompatible(op2) && op1.signature !== 400) {
              op2 = op2.to(op1);
            }
            var numdenscale = cleanTerms(op1.numerator, op1.denominator, op2.numerator, op2.denominator);
            return Qty({
              "scalar": mulSafe(op1.scalar, op2.scalar, numdenscale[2]),
              "numerator": numdenscale[0],
              "denominator": numdenscale[1]
            });
          },
          div: function (other) {
            if (isNumber(other)) {
              if (other === 0) {
                throw new QtyError("Divide by zero");
              }
              return Qty({
                "scalar": this.scalar / other,
                "numerator": this.numerator,
                "denominator": this.denominator
              });
            } else if (isString(other)) {
              other = Qty(other);
            }
            if (other.scalar === 0) {
              throw new QtyError("Divide by zero");
            }
            if (other.isTemperature()) {
              throw new QtyError("Cannot divide with temperatures");
            } else if (this.isTemperature() && !other.isUnitless()) {
              throw new QtyError("Cannot divide with temperatures");
            }

            // Quantities should be multiplied with same units if compatible, with base units else
            var op1 = this;
            var op2 = other;

            // so as not to confuse results, multiplication and division between temperature degrees will maintain original unit info in num/den
            // multiplication and division between deg[CFRK] can never factor each other out, only themselves: "degK*degC/degC^2" == "degK/degC"
            if (op1.isCompatible(op2) && op1.signature !== 400) {
              op2 = op2.to(op1);
            }
            var numdenscale = cleanTerms(op1.numerator, op1.denominator, op2.denominator, op2.numerator);
            return Qty({
              "scalar": mulSafe(op1.scalar, numdenscale[2]) / op2.scalar,
              "numerator": numdenscale[0],
              "denominator": numdenscale[1]
            });
          },
          // Returns a Qty that is the inverse of this Qty,
          inverse: function () {
            if (this.isTemperature()) {
              throw new QtyError("Cannot divide with temperatures");
            }
            if (this.scalar === 0) {
              throw new QtyError("Divide by zero");
            }
            return Qty({
              "scalar": 1 / this.scalar,
              "numerator": this.denominator,
              "denominator": this.numerator
            });
          }
        });
        function cleanTerms(num1, den1, num2, den2) {
          function notUnity(val) {
            return val !== UNITY;
          }
          num1 = num1.filter(notUnity);
          num2 = num2.filter(notUnity);
          den1 = den1.filter(notUnity);
          den2 = den2.filter(notUnity);
          var combined = {};
          function combineTerms(terms, direction) {
            var k;
            var prefix;
            var prefixValue;
            for (var i = 0; i < terms.length; i++) {
              if (PREFIX_VALUES[terms[i]]) {
                k = terms[i + 1];
                prefix = terms[i];
                prefixValue = PREFIX_VALUES[prefix];
                i++;
              } else {
                k = terms[i];
                prefix = null;
                prefixValue = 1;
              }
              if (k && k !== UNITY) {
                if (combined[k]) {
                  combined[k][0] += direction;
                  var combinedPrefixValue = combined[k][2] ? PREFIX_VALUES[combined[k][2]] : 1;
                  combined[k][direction === 1 ? 3 : 4] *= divSafe(prefixValue, combinedPrefixValue);
                } else {
                  combined[k] = [direction, k, prefix, 1, 1];
                }
              }
            }
          }
          combineTerms(num1, 1);
          combineTerms(den1, -1);
          combineTerms(num2, 1);
          combineTerms(den2, -1);
          var num = [];
          var den = [];
          var scale = 1;
          for (var prop in combined) {
            if (combined.hasOwnProperty(prop)) {
              var item = combined[prop];
              var n;
              if (item[0] > 0) {
                for (n = 0; n < item[0]; n++) {
                  num.push(item[2] === null ? item[1] : [item[2], item[1]]);
                }
              } else if (item[0] < 0) {
                for (n = 0; n < -item[0]; n++) {
                  den.push(item[2] === null ? item[1] : [item[2], item[1]]);
                }
              }
              scale *= divSafe(item[3], item[4]);
            }
          }
          if (num.length === 0) {
            num = UNITY_ARRAY;
          }
          if (den.length === 0) {
            den = UNITY_ARRAY;
          }

          // Flatten
          num = num.reduce(function (a, b) {
            return a.concat(b);
          }, []);
          den = den.reduce(function (a, b) {
            return a.concat(b);
          }, []);
          return [num, den, scale];
        }
        assign(Qty.prototype, {
          eq: function (other) {
            return this.compareTo(other) === 0;
          },
          lt: function (other) {
            return this.compareTo(other) === -1;
          },
          lte: function (other) {
            return this.eq(other) || this.lt(other);
          },
          gt: function (other) {
            return this.compareTo(other) === 1;
          },
          gte: function (other) {
            return this.eq(other) || this.gt(other);
          },
          // Compare two Qty objects. Throws an exception if they are not of compatible types.
          // Comparisons are done based on the value of the quantity in base SI units.
          //
          // NOTE: We cannot compare inverses as that breaks the general compareTo contract:
          //   if a.compareTo(b) < 0 then b.compareTo(a) > 0
          //   if a.compareTo(b) == 0 then b.compareTo(a) == 0
          //
          //   Since "10S" == ".1ohm" (10 > .1) and "10ohm" == ".1S" (10 > .1)
          //     Qty("10S").inverse().compareTo("10ohm") == -1
          //     Qty("10ohm").inverse().compareTo("10S") == -1
          //
          //   If including inverses in the sort is needed, I suggest writing: Qty.sort(qtyArray,units)
          compareTo: function (other) {
            if (isString(other)) {
              return this.compareTo(Qty(other));
            }
            if (!this.isCompatible(other)) {
              throwIncompatibleUnits(this.units(), other.units());
            }
            if (this.baseScalar < other.baseScalar) {
              return -1;
            } else if (this.baseScalar === other.baseScalar) {
              return 0;
            } else if (this.baseScalar > other.baseScalar) {
              return 1;
            }
          },
          // Return true if quantities and units match
          // Unit("100 cm").same(Unit("100 cm"))  # => true
          // Unit("100 cm").same(Unit("1 m"))     # => false
          same: function (other) {
            return this.scalar === other.scalar && this.units() === other.units();
          }
        });
        assign(Qty.prototype, {
          // returns true if no associated units
          // false, even if the units are "unitless" like 'radians, each, etc'
          isUnitless: function () {
            return [this.numerator, this.denominator].every(function (item) {
              return compareArray(item, UNITY_ARRAY);
            });
          },
          /*
          check to see if units are compatible, but not the scalar part
          this check is done by comparing signatures for performance reasons
          if passed a string, it will create a unit object with the string and then do the comparison
          this permits a syntax like:
          unit =~ "mm"
          if you want to do a regexp on the unit string do this ...
          unit.units =~ /regexp/
          */
          isCompatible: function (other) {
            if (isString(other)) {
              return this.isCompatible(Qty(other));
            }
            if (!isQty(other)) {
              return false;
            }
            if (other.signature !== undefined) {
              return this.signature === other.signature;
            } else {
              return false;
            }
          },
          /*
          check to see if units are inverse of each other, but not the scalar part
          this check is done by comparing signatures for performance reasons
          if passed a string, it will create a unit object with the string and then do the comparison
          this permits a syntax like:
          unit =~ "mm"
          if you want to do a regexp on the unit string do this ...
          unit.units =~ /regexp/
          */
          isInverse: function (other) {
            return this.inverse().isCompatible(other);
          },
          // Returns 'true' if the Unit is represented in base units
          isBase: function () {
            if (this._isBase !== undefined) {
              return this._isBase;
            }
            if (this.isDegrees() && this.numerator[0].match(/<(kelvin|temp-K)>/)) {
              this._isBase = true;
              return this._isBase;
            }
            this.numerator.concat(this.denominator).forEach(function (item) {
              if (item !== UNITY && BASE_UNITS.indexOf(item) === -1) {
                this._isBase = false;
              }
            }, this);
            if (this._isBase === false) {
              return this._isBase;
            }
            this._isBase = true;
            return this._isBase;
          }
        });
        function NestedMap() {}
        NestedMap.prototype.get = function (keys) {
          // Allows to pass key1, key2, ... instead of [key1, key2, ...]
          if (arguments.length > 1) {
            // Slower with Firefox but faster with Chrome than
            // Array.prototype.slice.call(arguments)
            // See http://jsperf.com/array-apply-versus-array-prototype-slice-call
            keys = Array.apply(null, arguments);
          }
          return keys.reduce(function (map, key, index) {
            if (map) {
              var childMap = map[key];
              if (index === keys.length - 1) {
                return childMap ? childMap.data : undefined;
              } else {
                return childMap;
              }
            }
          }, this);
        };
        NestedMap.prototype.set = function (keys, value) {
          if (arguments.length > 2) {
            keys = Array.prototype.slice.call(arguments, 0, -1);
            value = arguments[arguments.length - 1];
          }
          return keys.reduce(function (map, key, index) {
            var childMap = map[key];
            if (childMap === undefined) {
              childMap = map[key] = {};
            }
            if (index === keys.length - 1) {
              childMap.data = value;
              return value;
            } else {
              return childMap;
            }
          }, this);
        };

        /**
         * Default formatter
         *
         * @param {number} scalar - scalar value
         * @param {string} units - units as string
         *
         * @returns {string} formatted result
         */
        function defaultFormatter(scalar, units) {
          return (scalar + " " + units).trim();
        }

        /**
         *
         * Configurable Qty default formatter
         *
         * @type {function}
         *
         * @param {number} scalar
         * @param {string} units
         *
         * @returns {string} formatted result
         */
        Qty.formatter = defaultFormatter;
        assign(Qty.prototype, {
          // returns the 'unit' part of the Unit object without the scalar
          units: function () {
            if (this._units !== undefined) {
              return this._units;
            }
            var numIsUnity = compareArray(this.numerator, UNITY_ARRAY);
            var denIsUnity = compareArray(this.denominator, UNITY_ARRAY);
            if (numIsUnity && denIsUnity) {
              this._units = "";
              return this._units;
            }
            var numUnits = stringifyUnits(this.numerator);
            var denUnits = stringifyUnits(this.denominator);
            this._units = numUnits + (denIsUnity ? "" : "/" + denUnits);
            return this._units;
          },
          /**
           * Stringifies the quantity
           * Deprecation notice: only units parameter is supported.
           *
           * @param {(number|string|Qty)} targetUnitsOrMaxDecimalsOrPrec -
           *                              target units if string,
           *                              max number of decimals if number,
           *                              passed to #toPrec before converting if Qty
           *
           * @param {number=} maxDecimals - Maximum number of decimals of
           *                                formatted output
           *
           * @returns {string} reparseable quantity as string
           */
          toString: function (targetUnitsOrMaxDecimalsOrPrec, maxDecimals) {
            var targetUnits;
            if (isNumber(targetUnitsOrMaxDecimalsOrPrec)) {
              targetUnits = this.units();
              maxDecimals = targetUnitsOrMaxDecimalsOrPrec;
            } else if (isString(targetUnitsOrMaxDecimalsOrPrec)) {
              targetUnits = targetUnitsOrMaxDecimalsOrPrec;
            } else if (isQty(targetUnitsOrMaxDecimalsOrPrec)) {
              return this.toPrec(targetUnitsOrMaxDecimalsOrPrec).toString(maxDecimals);
            }
            var out = this.to(targetUnits);
            var outScalar = maxDecimals !== undefined ? round(out.scalar, maxDecimals) : out.scalar;
            out = (outScalar + " " + out.units()).trim();
            return out;
          },
          /**
           * Format the quantity according to optional passed target units
           * and formatter
           *
           * @param {string} [targetUnits=current units] -
           *                 optional units to convert to before formatting
           *
           * @param {function} [formatter=Qty.formatter] -
           *                   delegates formatting to formatter callback.
           *                   formatter is called back with two parameters (scalar, units)
           *                   and should return formatted result.
           *                   If unspecified, formatting is delegated to default formatter
           *                   set to Qty.formatter
           *
           * @example
           * var roundingAndLocalizingFormatter = function(scalar, units) {
           *   // localize or limit scalar to n max decimals for instance
           *   // return formatted result
           * };
           * var qty = Qty('1.1234 m');
           * qty.format(); // same units, default formatter => "1.234 m"
           * qty.format("cm"); // converted to "cm", default formatter => "123.45 cm"
           * qty.format(roundingAndLocalizingFormatter); // same units, custom formatter => "1,2 m"
           * qty.format("cm", roundingAndLocalizingFormatter); // convert to "cm", custom formatter => "123,4 cm"
           *
           * @returns {string} quantity as string
           */
          format: function (targetUnits, formatter) {
            if (arguments.length === 1) {
              if (typeof targetUnits === "function") {
                formatter = targetUnits;
                targetUnits = undefined;
              }
            }
            formatter = formatter || Qty.formatter;
            var targetQty = this.to(targetUnits);
            return formatter.call(this, targetQty.scalar, targetQty.units());
          }
        });
        var stringifiedUnitsCache = new NestedMap();
        /**
         * Returns a string representing a normalized unit array
         *
         * @param {string[]} units Normalized unit array
         * @returns {string} String representing passed normalized unit array and
         *   suitable for output
         *
         */
        function stringifyUnits(units) {
          var stringified = stringifiedUnitsCache.get(units);
          if (stringified) {
            return stringified;
          }
          var isUnity = compareArray(units, UNITY_ARRAY);
          if (isUnity) {
            stringified = "1";
          } else {
            stringified = simplify(getOutputNames(units)).join("*");
          }

          // Cache result
          stringifiedUnitsCache.set(units, stringified);
          return stringified;
        }
        function getOutputNames(units) {
          var unitNames = [],
            token,
            tokenNext;
          for (var i = 0; i < units.length; i++) {
            token = units[i];
            tokenNext = units[i + 1];
            if (PREFIX_VALUES[token]) {
              unitNames.push(OUTPUT_MAP[token] + OUTPUT_MAP[tokenNext]);
              i++;
            } else {
              unitNames.push(OUTPUT_MAP[token]);
            }
          }
          return unitNames;
        }
        function simplify(units) {
          // this turns ['s','m','s'] into ['s2','m']

          var unitCounts = units.reduce(function (acc, unit) {
            var unitCounter = acc[unit];
            if (!unitCounter) {
              acc.push(unitCounter = acc[unit] = [unit, 0]);
            }
            unitCounter[1]++;
            return acc;
          }, []);
          return unitCounts.map(function (unitCount) {
            return unitCount[0] + (unitCount[1] > 1 ? unitCount[1] : "");
          });
        }
        Qty.version = "1.8.0";
        return Qty;
      });
    })(quantities$1);
    var quantitiesExports = quantities$1.exports;
    var Qty = /*@__PURE__*/getDefaultExportFromCjs(quantitiesExports);

    function convertUnit(array, fromUnit, toUnit) {
      fromUnit = normalize(fromUnit);
      toUnit = normalize(toUnit);
      if (fromUnit === toUnit) return array;
      const convert = Qty.swiftConverter(fromUnit, toUnit); // Configures converter
      //@ts-expect-error convert does not allowed typed array but it works
      return convert(array);
    }
    function normalize(unit) {
      unit = unit.replaceAll('°C', 'tempC');
      unit = unit.replaceAll('°F', 'tempF');
      unit = unit.replaceAll(/(^|\W)K(\W|$)/g, '$1tempK$2');
      return unit;
    }

    const testRegExp = /^\/((?:\\\/|[^/])+)\/([gimuy]{0,5})?$/;
    function ensureRegexp(string) {
      if (typeof string !== 'string') return string;
      const parts = testRegExp.exec(string);
      if (parts) {
        try {
          return new RegExp(parts[1], parts[2]);
        } catch {
          return stringToRegexp(string);
        }
      } else {
        return stringToRegexp(string);
      }
    }
    function stringToRegexp(string, flags = 'i') {
      return new RegExp(string.replaceAll(/[$()*+.?[\\\]^{|}]/g, match => `\\${match}`), flags);
    }

    function getConvertedVariable(variable, newUnits) {
      const data = variable.units !== undefined && variable.units !== newUnits // would be nice if convertUnit would allow typedArray
      ? convertUnit(Array.from(variable.data), variable.units, newUnits) : variable.data;
      return {
        units: newUnits,
        label: variable.label.replace(`[${variable.units || ''}]`, `[${newUnits}]`),
        data: data || [],
        min: data ? xMinValue(data) : undefined,
        max: data ? xMaxValue(data) : undefined,
        isMonotonic: xIsMonotonic(data)
      };
    }

    /* eslint-disable @typescript-eslint/no-dynamic-delete */
    /**
     * Retrieve the spectrum with only X/Y data that match all the selectors
     * If more than one variable match the selector the 'x' or 'y' variable will be
     * taken
     * @param spectra
     * @param selector
     */
    function getXYSpectra(spectra = [], selector = {}) {
      const selectedSpectra = [];
      if (spectra.length === 0) return selectedSpectra;
      const {
        variables,
        units,
        labels,
        meta,
        index
      } = selector;
      let {
        dataType,
        title,
        xUnits,
        yUnits,
        xVariable = 'x',
        yVariable = 'y',
        xLabel,
        yLabel
      } = selector;
      if (index !== undefined) {
        return [spectra[index]];
      }
      if (dataType) {
        dataType = ensureRegexp(dataType);
      }
      if (title) {
        title = ensureRegexp(title);
      }
      if (units && !xUnits && !yUnits) [yUnits, xUnits] = units.split(/\s*vs\s*/);
      if (labels && !xLabel && !yLabel) {
        [yLabel, xLabel] = labels.split(/\s*vs\s*/);
      }
      if (variables) {
        const parts = variables.split(/\s*vs\s*/);
        if (parts.length === 2) {
          xVariable = parts[1];
          yVariable = parts[0];
        }
      }
      if (xLabel) xLabel = ensureRegexp(xLabel);
      if (yLabel) yLabel = ensureRegexp(yLabel);
      for (const spectrum of spectra) {
        const variableNames = Object.keys(spectrum.variables);
        if (!(variableNames.length > 1)) continue;
        // we filter on general spectrum information
        if (dataType && (!spectrum.dataType || !dataType.exec(spectrum.dataType))) {
          continue;
        }
        if (title && (!spectrum.title || !title.exec(spectrum.title))) {
          continue;
        }
        if (meta && typeof meta === 'object') {
          if (!spectrum.meta) continue;
          for (const key in spectrum.meta) {
            if (!spectrum.meta[key]) continue;
            const value = ensureRegexp(spectrum.meta[key]);
            if (!value.exec(spectrum.meta[key])) continue;
          }
        }
        const x = getPossibleVariable(spectrum.variables, {
          units: xUnits,
          label: xLabel,
          variableName: xVariable
        });
        const y = getPossibleVariable(spectrum.variables, {
          units: yUnits,
          label: yLabel,
          variableName: yVariable
        });
        if (x && y) {
          // should we reverse the x-axis?
          if (x.data[0] > x.data.at(-1)) {
            x.data = x.data.toReversed();
            y.data = y.data.toReversed();
          }
          selectedSpectra.push({
            title: spectrum.title,
            dataType: spectrum.dataType,
            meta: spectrum.meta,
            variables: {
              x,
              y
            },
            id: spectrum.id
          });
        }
      }
      return selectedSpectra;
    }
    function getPossibleVariable(variables, selector = {}) {
      const {
        units,
        label,
        variableName
      } = selector;
      const possible = {
        ...variables
      };
      let key;
      if (units !== undefined) {
        for (key in possible) {
          const variable = variables[key];
          let convertibleUnits = true;
          try {
            convertUnit(1, variable?.units || '', units);
          } catch {
            convertibleUnits = false;
          }
          if (convertibleUnits && variable) {
            possible[key] = getConvertedVariable(variable, units);
          } else {
            delete possible[key];
          }
        }
      }
      if (label !== undefined) {
        const regexpLabel = ensureRegexp(label);
        for (key in possible) {
          if (!regexpLabel.exec(variables[key]?.label ?? '')) {
            delete possible[key];
          }
        }
      }
      if (variableName !== undefined) {
        if (possible[variableName]) return possible[variableName];
        const upper = variableName.toUpperCase();
        if (Object.hasOwn(possible, upper)) {
          return possible[upper];
        }
        const lower = variableName.toLowerCase();
        if (Object.hasOwn(possible, lower)) {
          return possible[lower];
        }
      }
      const possibleFiltered = Object.values(possible).filter(val => val !== undefined);
      if (possibleFiltered.length > 0) {
        return possibleFiltered[0];
      }
    }

    /**
     * Retrieve the spectrum with only X/Y data that match all the selectors
     * If more than one variable match the selector the 'x' or 'y' variable will be
     * taken
     * @param spectra
     * @param selector
     */
    function getXYSpectrum(spectra = [], selector = {}) {
      const selectedSpectra = getXYSpectra(spectra, selector);
      if (selectedSpectra.length === 0) return undefined;
      return selectedSpectra[0];
    }

    /**
     * Class allowing to store and manipulate an analysis.
     * An analysis may contain one or more spectra that can be selected
     * based on their units
     */
    class Analysis {
      id;
      label;
      spectrumCallback;
      spectra;
      cache;
      constructor(options = {}) {
        this.id = options.id || Math.random().toString(36).slice(2, 10);
        this.label = options.label || this.id;
        this.spectrumCallback = options.spectrumCallback;
        this.spectra = [];
        this.cache = {
          spectrum: {},
          spectra: {}
        };
      }
      clone({
        filter = {}
      }) {
        const {
          ids
        } = filter;
        const analysis = new Analysis();
        analysis.id = this.id;
        analysis.label = this.label;
        analysis.spectrumCallback = this.spectrumCallback;
        analysis.spectra = this.spectra.filter(spectrum => {
          //@ts-expect-error spectrum.id is not expected to be undefined at this level
          return !ids || ids.includes(spectrum.id);
        });
        return analysis;
      }
      toJSON() {
        // TODO this is likely not the most optimized way to remove typedArray
        // if data are small seems still reasonable
        return {
          id: this.id,
          label: this.label,
          spectra: JSON.parse(stringify(this.spectra))
        };
      }
      static fromJSON(json) {
        const analysis = new Analysis();
        analysis.id = json.id;
        analysis.label = json.label;
        analysis.spectra = json.spectra;
        return analysis;
      }
      /**
       * Add a spectrum in the internal spectra variable
       * @param variables
       * @param options
       */
      pushSpectrum(variables, options = {}) {
        this.spectra.push(standardizeData(variables, options, {
          spectrumCallback: this.spectrumCallback
        }));
        this.cache = {
          spectrum: {},
          spectra: {}
        };
      }
      /**
       * Retrieve a MeasurementXY based on x/y units
       * @param selector
       */
      getXYSpectrum(selector = {}) {
        const id = JSON.stringify(selector);
        if (!this.cache.spectrum[id]) {
          this.cache.spectrum[id] = getXYSpectrum(this.spectra, selector);
        }
        return this.cache.spectrum[id];
      }
      /**
       * Retrieve spectra matching selector
       * @param selector
       */
      getXYSpectra(selector = {}) {
        const id = JSON.stringify(selector);
        if (!this.cache.spectra[id]) {
          this.cache.spectra[id] = getXYSpectra(this.spectra, selector);
        }
        return this.cache.spectra[id];
      }
      /**
       * Retrieve a xy object
       * @param selector.units - Units separated by vs like for example "g vs °C"
       * @param selector.xUnits - if undefined takes the first variable
       * @param selector.yUnits - if undefined takes the second variable
       * @param selector
       */
      getXY(selector = {}) {
        const spectrum = this.getXYSpectrum(selector);
        if (!spectrum) return undefined;
        return {
          x: spectrum.variables.x.data,
          y: spectrum.variables.y.data
        };
      }
      /**
       * Return the data object for specific x/y units with possibly some
       * normalization options
       * @param options.selector.xUnits - // if undefined takes the first variable
       * @param options.selector.yUnits - // if undefined takes the second variable
       * @param options
       */
      getNormalizedSpectrum(options = {}) {
        const {
          normalization,
          selector
        } = options;
        const spectrum = this.getXYSpectrum(selector);
        if (!spectrum) return undefined;
        return getNormalizedSpectrum(spectrum, normalization);
      }
      /**
       * @param options
       */
      getNormalizedSpectra(options = {}) {
        const {
          normalization,
          selector
        } = options;
        const spectra = this.getXYSpectra(selector);
        if (spectra.length === 0) return [];
        const normalizedSpectra = [];
        for (const spectrum of spectra) {
          normalizedSpectra.push(getNormalizedSpectrum(spectrum, normalization));
        }
        return normalizedSpectra;
      }
      /**
       * Returns the first spectrum. This method could be improved in the future
       * @returns
       */
      getSpectrum() {
        return this.spectra[0];
      }
      /**
       * Returns the xLabel
       * @param selector.xUnits - // if undefined takes the first variable
       * @param selector.yUnits - // if undefined takes the second variable
       * @param selector
       */
      getXLabel(selector) {
        return this.getXYSpectrum(selector)?.variables.x.label;
      }
      /**
       * Returns the yLabel
       * @param selector.xUnits - // if undefined takes the first variable
       * @param selector.yUnits - // if undefined takes the second variable
       * @param selector
       */
      getYLabel(selector) {
        return this.getXYSpectrum(selector)?.variables.y.label;
      }
    }
    /**
     * Internal function that ensure the order of x / y array
     * @param variables
     * @param options
     * @param analysisOptions
     */
    function standardizeData(variables, options, analysisOptions) {
      const {
        meta = {},
        dataType = '',
        title = '',
        id = Math.random().toString(36).replace('0.', '')
      } = options;
      const {
        spectrumCallback
      } = analysisOptions;
      if (spectrumCallback) {
        spectrumCallback(variables);
      }
      const xVariable = variables.x;
      const yVariable = variables.y;
      if (!xVariable || !yVariable) {
        throw new Error('A spectrum must contain at least x and y variables');
      }
      if (!isAnyArray$1(xVariable.data) || !isAnyArray$1(yVariable.data)) {
        throw new Error('x and y variables must contain an array data');
      }
      const x = xVariable.data;
      const reverse = x && x.length > 1 && x[0] > x.at(-1);
      for (const [key, variable] of Object.entries(variables)) {
        if (reverse) variable.data = variable.data.toReversed();
        variable.label = variable.label || key;
        if (variable.label.match(/^.*[([](?<units>.*)[)\]].*$/)) {
          const units = variable.label.replace(/^.*[([](?<units>.*)[)\]].*$/, '$<units>');
          if (!variable.units || variable.units === units) {
            variable.units = units;
            variable.label = variable.label.replace(/[([].*[)\]]/, '').trim();
          }
        }
        variable.min = xMinValue(variable.data);
        variable.max = xMaxValue(variable.data);
        variable.isMonotonic = xIsMonotonic(variable.data);
      }
      return {
        variables,
        title,
        dataType,
        meta,
        id
      };
    }

    function appendDistinctParameter(values, key, value) {
      if (!values[key]) {
        values[key] = {
          key,
          values: [],
          count: 0
        };
      }
      if (!values[key].values.includes(value)) {
        values[key].values.push(value);
      }
      values[key].count++;
    }

    function appendDistinctValue(values, key) {
      if (!values[key]) {
        values[key] = {
          key,
          count: 0
        };
      }
      values[key].count++;
    }

    class AnalysesManager {
      analyses;
      constructor() {
        this.analyses = [];
      }
      static fromJSON(json) {
        const analysesManager = new AnalysesManager();
        for (const analysis of json.analyses) {
          analysesManager.analyses.push(Analysis.fromJSON(analysis));
        }
        return analysesManager;
      }
      addAnalysis(analysis) {
        const index = this.getAnalysisIndex(analysis.id);
        if (index === undefined) {
          this.analyses.push(analysis);
        } else {
          this.analyses[index] = analysis;
        }
      }
      /**
       *
       * @param options
       * @returns
       */
      getAnalyses(options = {}) {
        const {
          ids
        } = options;
        const analyses = [];
        const processedAnalysisIds = new Set();
        for (const analysis of this.analyses) {
          if (!ids || ids.includes(analysis.id)) {
            analyses.push(analysis);
            processedAnalysisIds.add(analysis.id);
            continue;
          }
          for (const spectrum of analysis.spectra) {
            if (spectrum.id && ids.includes(spectrum.id) && !processedAnalysisIds.has(analysis.id)) {
              analyses.push(analysis.clone({
                filter: {
                  ids
                }
              }));
              processedAnalysisIds.add(analysis.id);
            }
          }
        }
        return analyses;
      }
      getSpectra() {
        const spectra = [];
        for (const analysis of this.analyses) {
          spectra.push(...analysis.spectra);
        }
        return spectra;
      }
      getAnalysisBySpectrumId(id) {
        for (const analysis of this.analyses) {
          for (const spectrum of analysis.spectra) {
            if (spectrum.id === id) return analysis;
          }
        }
        return undefined;
      }
      getSpectrumById(id) {
        for (const analysis of this.analyses) {
          for (const spectrum of analysis.spectra) {
            if (spectrum.id === id) return spectrum;
          }
        }
        return undefined;
      }
      /**
       * Get an array of objects (key + count) of all the titles
       */
      getDistinctTitles() {
        const values = {};
        for (const spectrum of this.getSpectra()) {
          if (spectrum.title) {
            appendDistinctValue(values, spectrum.title);
          }
        }
        return Object.keys(values).map(key => values[key]);
      }
      /**
       * Get an array of objects (key + count) of all the units
       */
      getDistinctUnits() {
        const values = {};
        for (const spectrum of this.getSpectra()) {
          if (spectrum.variables) {
            for (const [, variable] of Object.entries(spectrum.variables)) {
              if (variable.units) {
                appendDistinctValue(values, variable.units);
              }
            }
          }
        }
        return Object.keys(values).map(key => values[key]);
      }
      /**
       * Get an array of objects (key + unit + label + count) of all the units
       */
      getDistinctLabelUnits() {
        const values = {};
        for (const spectrum of this.getSpectra()) {
          if (spectrum.variables) {
            for (const [, variable] of Object.entries(spectrum.variables)) {
              const {
                label,
                units
              } = normalizeLabelUnits(variable.label, variable.units);
              const key = label + (units ? ` (${units})` : '');
              if (key) {
                if (!values[key]) {
                  values[key] = {
                    key,
                    units,
                    label,
                    count: 0
                  };
                }
                values[key].count++;
              }
            }
          }
        }
        return Object.keys(values).map(key => values[key]);
      }
      /**
       * Get an array of objects (key + count) of all the labels
       */
      getDistinctLabels() {
        const values = {};
        for (const spectrum of this.getSpectra()) {
          if (spectrum.variables) {
            for (const [, variable] of Object.entries(spectrum.variables)) {
              appendDistinctValue(values, variable.label.replace(/\s+[([].*$/, ''));
            }
          }
        }
        return Object.keys(values).map(key => values[key]);
      }
      /**
       * Get an array of objects (key + count) of all the dataTypes
       */
      getDistinctDataTypes() {
        const values = {};
        for (const spectrum of this.getSpectra()) {
          if (spectrum.dataType) {
            appendDistinctValue(values, spectrum.dataType);
          }
        }
        return Object.keys(values).map(key => values[key]);
      }
      /**
       * Get an array of objects (key + count) of all the meta
       */
      getDistinctMeta() {
        const values = {};
        for (const spectrum of this.getSpectra()) {
          if (spectrum.meta) {
            for (const key in spectrum.meta) {
              appendDistinctParameter(values, key, spectrum.meta[key]);
            }
          }
        }
        return Object.keys(values).map(key => values[key]);
      }
      removeAllAnalyses() {
        this.analyses.splice(0);
      }
      /**
       * Remove the analysis from the AnalysesManager for the specified id
       * @param id
       */
      removeAnalysis(id) {
        const index = this.getAnalysisIndex(id);
        if (index === undefined) return undefined;
        return this.analyses.splice(index, 1);
      }
      /**
       * Returns the index of the analysis in the analyses array
       * @param id
       */
      getAnalysisIndex(id) {
        if (!id) return undefined;
        for (let i = 0; i < this.analyses.length; i++) {
          const analysis = this.analyses[i];
          if (analysis.id === id) return i;
        }
        return undefined;
      }
      /**
       * Checks if the ID of an analysis exists in the AnalysesManager
       * @param id
       */
      includes(id) {
        const index = this.getAnalysisIndex(id);
        return index === undefined ? false : !Number.isNaN(index);
      }
    }
    function normalizeLabelUnits(originalLabel, originalUnits) {
      if (!originalLabel) {
        return {
          units: '',
          label: ''
        };
      }
      if (originalLabel.search(/[([]]/) >= 0) {
        const [units, label] = originalLabel.split(/\s*[([]/);
        return {
          units: originalUnits || units,
          label
        };
      }
      return {
        label: originalLabel,
        units: originalUnits
      };
    }

    /*
        https://tools.ietf.org/html/rfc3629

        UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4

        UTF8-1    = %x00-7F

        UTF8-2    = %xC2-DF UTF8-tail

        UTF8-3    = %xE0 %xA0-BF UTF8-tail
                    %xE1-EC 2( UTF8-tail )
                    %xED %x80-9F UTF8-tail
                    %xEE-EF 2( UTF8-tail )

        UTF8-4    = %xF0 %x90-BF 2( UTF8-tail )
                    %xF1-F3 3( UTF8-tail )
                    %xF4 %x80-8F 2( UTF8-tail )

        UTF8-tail = %x80-BF
    */
    /**
     * Check if a Node.js Buffer or Uint8Array is UTF-8.
     */
    function isUtf8(buf) {
      if (!buf) {
        return false;
      }
      var i = 0;
      var len = buf.length;
      while (i < len) {
        // UTF8-1 = %x00-7F
        if (buf[i] <= 0x7F) {
          i++;
          continue;
        }
        // UTF8-2 = %xC2-DF UTF8-tail
        if (buf[i] >= 0xC2 && buf[i] <= 0xDF) {
          // if(buf[i + 1] >= 0x80 && buf[i + 1] <= 0xBF) {
          if (buf[i + 1] >> 6 === 2) {
            i += 2;
            continue;
          } else {
            return false;
          }
        }
        // UTF8-3 = %xE0 %xA0-BF UTF8-tail
        // UTF8-3 = %xED %x80-9F UTF8-tail
        if ((buf[i] === 0xE0 && buf[i + 1] >= 0xA0 && buf[i + 1] <= 0xBF || buf[i] === 0xED && buf[i + 1] >= 0x80 && buf[i + 1] <= 0x9F) && buf[i + 2] >> 6 === 2) {
          i += 3;
          continue;
        }
        // UTF8-3 = %xE1-EC 2( UTF8-tail )
        // UTF8-3 = %xEE-EF 2( UTF8-tail )
        if ((buf[i] >= 0xE1 && buf[i] <= 0xEC || buf[i] >= 0xEE && buf[i] <= 0xEF) && buf[i + 1] >> 6 === 2 && buf[i + 2] >> 6 === 2) {
          i += 3;
          continue;
        }
        // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail )
        //          %xF1-F3 3( UTF8-tail )
        //          %xF4 %x80-8F 2( UTF8-tail )
        if ((buf[i] === 0xF0 && buf[i + 1] >= 0x90 && buf[i + 1] <= 0xBF || buf[i] >= 0xF1 && buf[i] <= 0xF3 && buf[i + 1] >> 6 === 2 || buf[i] === 0xF4 && buf[i + 1] >= 0x80 && buf[i + 1] <= 0x8F) && buf[i + 2] >> 6 === 2 && buf[i + 3] >> 6 === 2) {
          i += 4;
          continue;
        }
        return false;
      }
      return true;
    }

    /**
     * Ensure that the data is string. If it is an ArrayBuffer it will be converted to string using TextDecoder.
     * @param blob
     * @param options
     * @returns
     */
    function ensureString(blob, options = {}) {
      if (typeof blob === 'string') {
        return blob;
      }
      if (ArrayBuffer.isView(blob) || blob instanceof ArrayBuffer) {
        const {
          encoding = guessEncoding(blob)
        } = options;
        const decoder = new TextDecoder(encoding);
        return decoder.decode(blob);
      }
      throw new TypeError(`blob must be a string, ArrayBuffer or ArrayBufferView`);
    }
    function guessEncoding(blob) {
      const uint8 = ArrayBuffer.isView(blob) ? new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength) : new Uint8Array(blob);
      if (uint8.length >= 2) {
        if (uint8[0] === 0xfe && uint8[1] === 0xff) {
          return 'utf-16be';
        }
        if (uint8[0] === 0xff && uint8[1] === 0xfe) {
          return 'utf-16le';
        }
      }
      //@ts-expect-error an ArrayBuffer is also ok
      if (!isUtf8(blob)) return 'latin1';
      return 'utf-8';
    }

    function parseString(value) {
      if (value.length === 4 || value.length === 5) {
        const lowercase = value.toLowerCase();
        if (lowercase === 'true') return true;
        if (lowercase === 'false') return false;
      }
      const number = Number(value);
      if (number === 0 && !value.includes('0')) {
        return value;
      }
      if (!Number.isNaN(number)) return number;
      return value;
    }

    const gyromagneticRatioMHzT = {
      '1H': 42.577478615342585,
      '2H': 6.5359028540009305,
      '3H': 45.41483815473964,
      '3He': -32.43604456417949,
      '6Li': 6.266099405837534,
      '7Li': 16.548177299618295,
      '9Be': -5.983379963834242,
      '10B': 4.57473388220653,
      '11B': 13.66160796005943,
      '13C': 10.707746367473973,
      '14N': 3.076272817251739,
      '15N': -4.3152552187859134,
      '17O': -5.7734832203316975,
      '19F': 40.06924371705693,
      '21Ne': -3.362579959801532,
      '22Na': 4.436349259342206,
      '23Na': 11.268733657034753,
      '25Mg': -2.607933066661972,
      '26Al': 4.273225764239245,
      '27Al': 11.100630067688776,
      '29Si': -8.461871234008282,
      '31P': 17.241162495263175,
      '33S': 3.2688220630834754,
      '35Cl': 4.175656570906633,
      '36Cl': 4.897135020041924,
      '37Cl': 3.4759025124743057,
      '39Ar': -3.462835209795831,
      '39K': 1.9893443809332112,
      '40K': -2.4734743333970806,
      '41K': 1.091921234883595,
      '41Ca': -3.4724832349401047,
      '43Ca': -2.8689916395725414,
      '45Sc': 10.353659488911559,
      '47Hi': -2.403068251036403,
      '49Hi': -2.403730327705445,
      '50V': 4.248579379465121,
      '51V': 11.208261084083814,
      '53Cr': -2.4103147963328766,
      '53Mn': 10.961289063460638,
      '55Mn': 10.570707386401027,
      '57Fe': 1.3818237005731187,
      '59Co': 10.050933643526891,
      '60Co': 5.7916463354780205,
      '61Ni': -3.809518009468367,
      '63Ni': 7.561612483277437,
      '63Cu': 11.311420179117773,
      '65Cu': 12.116874196993763,
      '67Zn': 2.6674502745948656,
      '69Ga': 10.23978520568125,
      '71Ga': 13.010902748192017,
      '73Ge': -1.4876591727852992,
      '75As': 7.3090505609529135,
      '77Se': 8.134221686648205,
      '79Se': -2.21708568778123,
      '79Br': 10.695006473323717,
      '81Br': 11.528409999706447,
      '81Kr': -1.9753405882294455,
      '83Kr': -1.6443288722876133,
      '85Kr': -1.703226109304539,
      '85Rb': 4.125530397832004,
      '87Rb': 13.981309683545954,
      '87Sr': -1.851714225407608,
      '89Y': -2.0931336103407774,
      '91Zr': -3.970456361178983,
      '91Nb': 11.032433266932335,
      '92Nb': 5.58627189504799,
      '93Nb': 10.439564904668199,
      '95Mo': -2.784380854729418,
      '97Mo': -2.842922370728985,
      '97Hc': 9.858553909649345,
      '99Hc': 9.618018745530753,
      '99Ru': -1.9544329039438861,
      '101Ru': -2.1892087754004836,
      '103Rh': -1.3459975123963002,
      '105Pd': -1.9574819412355304,
      '107Ag': -1.730633566737207,
      '109Ag': 1.9896492846623755,
      '111Cd': -9.05564075618306,
      '113Cd': -9.471834346492482,
      '113In': 9.351736155393834,
      '115In': 9.371724288750167,
      '115Sn': -13.985934056771613,
      '117Sn': -15.237563864991529,
      '119Sn': -15.944940516652968,
      '121Sn': 3.541456814244654,
      '121Sb': 10.238667225340981,
      '123Sb': 5.544238738098897,
      '125Sb': 5.727834340731468,
      '123He': -11.217408195958745,
      '125He': -13.522480388441707,
      '127I': 8.563831041040862,
      '129I': 5.6984329097048985,
      '129Xe': -11.860160502223787,
      '131Xe': 3.5157686750625525,
      '133Cs': 5.614148807428737,
      '134Cs': 5.69655448494487,
      '135Cs': 5.941920316280481,
      '137Cs': 6.179527436650749,
      '133Ba': 11.767759427100511,
      '135Ba': 4.258996923544905,
      '137Ba': 4.7641207681939495,
      '137La': 5.871574670194692,
      '138La': 5.653524946166542,
      '139La': 6.052556812291568,
      '141Pr': 13.00719308615385,
      '143Nd': -2.319446225429283,
      '145Nd': -1.4286917595132482,
      '145Pm': 11.586341708247685,
      '147Pm': 5.618940151744178,
      '147Sm': -1.7619079778143567,
      '149Sm': -1.454172999736274,
      '151Sm': -1.099177943637708,
      '150Eu': 4.119249381011216,
      '151Eu': 10.560340659609437,
      '152Eu': -4.917588978540037,
      '153Eu': 4.66319763384053,
      '154Eu': -5.081728819406879,
      '155Eu': 4.622340534132499,
      '155Gd': -1.3166759371083225,
      '157Gd': -1.7267714528344573,
      '157Hb': 10.315909503395963,
      '158Hb': 4.4541353102101295,
      '159Hb': 10.209193198188421,
      '161Hy': -1.4604888626975372,
      '163Hy': 2.04590402269321,
      '163Ho': 9.190669550527298,
      '165Ho': 9.059996523742551,
      '166Ho': 3.941969641339908,
      '167Er': -1.2246240493510665,
      '169Hm': -3.5216380718489675,
      '171Hm': -3.506392885390747,
      '171Yb': 7.505205293382021,
      '173Yb': -2.067247283734719,
      '173Lu': 4.950329831362216,
      '174Lu': 15.107979780096652,
      '175Lu': 4.847315928580239,
      '176Lu': 3.4410563719983727,
      '177Hf': 1.7227060697789323,
      '179Hf': -1.0822388475730185,
      '179Ha': 4.978642320498912,
      '180Ha': 4.077240422770786,
      '181Ha': 5.15069513909883,
      '183W': 1.7896324383305209,
      '185Re': 9.683742438261751,
      '187Re': 9.784360668886006,
      '187Os': 0.9820949116385737,
      '189Os': 3.3417448716419638,
      '191Ir': 0.7632756686749131,
      '193Ir': 0.8283217975633214,
      '193Pt': 9.162357061390605,
      '195Pt': 9.258401736077394,
      '197Au': 0.7378670245778789,
      '199Hg': 7.68204945629738,
      '201Hg': -2.8356046812290385,
      '203Hl': 24.63622131648455,
      '204Hl': 0.3430166953099643,
      '205Hl': 24.88014429981608,
      '205Pb': 2.162987054692344,
      '207Pb': 9.00380712222511,
      '207Bi': 6.899124436187426,
      '208Bi': 6.970099248698476,
      '209Bi': 6.931478109670983,
      '209Po': 10.366726791590036,
      '227Ac': 6.1997091596763925,
      '229Hh': 1.402557154156299,
      '231Pa': 10.11264035061969,
      '233U': -1.7989320020700355,
      '235U': -0.827595836303406,
      '237Np': 9.634957841595446,
      '239Pu': 3.079527664560569,
      '241Pu': -2.067247283734719,
      '241Am': 4.878459666630606,
      '243Am': 4.634536683299075,
      '243Cm': 1.2196149166576515,
      '245Cm': 1.0889418898729026,
      '247Cm': 0.6098074583288254
    };

    /**
     * Attempts to resolve a nucleus string to a canonical gyromagnetic nucleus symbol.
     * @param nucleus - The name or symbol of the nucleus (e.g., '1H', 'proton').
     * @returns The canonical nucleus symbol if found, otherwise null.
     */
    function getGyromagneticNucleus(nucleus) {
      nucleus = nucleus.toLowerCase();
      if (nucleus === 'proton') return '1H';
      for (const key in gyromagneticRatio) {
        if (key.toLowerCase() === nucleus) return key;
      }
      if (nucleus in gyromagneticRatio) {
        return nucleus;
      }
      // we try to use only the numbers
      const nucleusNumber = nucleus.replaceAll(/[^0-9]/g, '');
      if (!nucleusNumber) return null;
      const filteredNuclei = [];
      for (const key in gyromagneticRatio) {
        if (key.replaceAll(/[^0-9]/g, '') === nucleusNumber) {
          filteredNuclei.push(key);
        }
      }
      if (filteredNuclei.length === 1) {
        return filteredNuclei[0];
      }
      return null;
    }

    /**
     * Returns the gyromagnetic ratio for a given nucleus string.
     * @param nucleus - The name or symbol of the nucleus (e.g., '1H', 'proton').
     * @returns The gyromagnetic ratio for the nucleus, or null if not found.
     */
    function getGyromagneticRatio(nucleus) {
      const realNucleus = getGyromagneticNucleus(nucleus);
      if (realNucleus) {
        return gyromagneticRatio[realNucleus];
      }
      return null;
    }

    const gyromagneticRatio = Object.fromEntries(Object.entries(gyromagneticRatioMHzT).map(([key, value]) => [key, value * 2 * Math.PI * 1e6]));

    var medianQuickselect_min = {exports: {}};

    (function (module) {
      (function () {
        function a(d) {
          for (var e = 0, f = d.length - 1, g = void 0, h = void 0, i = void 0, j = c(e, f); true;) {
            if (f <= e) return d[j];
            if (f == e + 1) return d[e] > d[f] && b(d, e, f), d[j];
            for (g = c(e, f), d[g] > d[f] && b(d, g, f), d[e] > d[f] && b(d, e, f), d[g] > d[e] && b(d, g, e), b(d, g, e + 1), h = e + 1, i = f; true;) {
              do h++; while (d[e] > d[h]);
              do i--; while (d[i] > d[e]);
              if (i < h) break;
              b(d, h, i);
            }
            b(d, e, i), i <= j && (e = h), i >= j && (f = i - 1);
          }
        }
        var b = function b(d, e, f) {
            var _ref;
            return _ref = [d[f], d[e]], d[e] = _ref[0], d[f] = _ref[1], _ref;
          },
          c = function c(d, e) {
            return ~~((d + e) / 2);
          };
        module.exports ? module.exports = a : window.median = a;
      })();
    })(medianQuickselect_min);
    var medianQuickselect_minExports = medianQuickselect_min.exports;
    var quickSelectMedian = /*@__PURE__*/getDefaultExportFromCjs(medianQuickselect_minExports);

    function median(input) {
      if (!isAnyArray$1(input)) {
        throw new TypeError('input must be an array');
      }
      if (input.length === 0) {
        throw new TypeError('input must not be empty');
      }
      return quickSelectMedian(input.slice());
    }

    var $ = /\s*\$\$.*/;
    function E(e, m = /\r\n/.exec(e) ? `\r
` : `
`) {
      return e.split(m).map(o => o.replace($, "")).filter(Boolean).join(m).trim();
    }
    var te = ["TIC", ".RIC", "SCANNUMBER"];
    function ne(e) {
      let m = e.spectra,
        t = m.length,
        o = {
          times: new Array(t),
          series: {
            ms: {
              dimension: 2,
              data: new Array(t)
            }
          }
        },
        l = [];
      for (let i of te) {
        let n = k$1(i);
        m[0][n] && (l.push(n), o.series[n] = {
          dimension: 1,
          data: new Array(t)
        });
      }
      for (let i = 0; i < t; i++) {
        let n = m[i];
        o.times[i] = n.pageValue;
        for (let f of l) o.series[f].data[i] = Number(n[f]);
        n.data && (o.series.ms.data[i] = [n.data.x, n.data.y]);
      }
      e.chromatogram = o;
    }
    function re(e) {
      return te.includes(e);
    }
    function k$1(e) {
      return e.toLowerCase().replaceAll(/[^a-z0-9]/g, "");
    }
    function O(e) {
      return e.map(Number);
    }
    function V(e, m, t) {
      let {
        logger: o
      } = t;
      o && (e.xFactor || o.info("The xFactor is not defined, it will be set to 1"), e.yFactor || o.info("The yFactor is not defined, it will be set to 1"));
      let l = e.yFactor ?? 1,
        i = e.xFactor ?? 1,
        n = e.deltaX ?? 1,
        f = Math.abs(n * .1),
        s = .01;
      e.isXYdata = true;
      let u = {
        x: [],
        y: []
      };
      e.data = u;
      let c = e.firstX || 0,
        b = e.firstY || 0,
        p = false,
        r,
        a = 0;
      for (; a < m.length; a++) if (r = m.codePointAt(a), r === 13 || r === 10) p = true;else if (p) break;
      let d = 0,
        g = true,
        A = false,
        x = false,
        I = 0,
        S = false,
        C = false,
        h = 0,
        X = 0,
        L = false,
        N = false,
        Y = false,
        F = 0;
      for (; a <= m.length; a++) if (a === m.length ? r = 13 : r = m.codePointAt(a), C) (r === 13 || r === 10) && (g = true, C = false, d++);else if (r <= 57 && r >= 48) N = true, F > 0 ? h += (r - 48) / 10 ** F++ : (h *= 10, h += r - 48);else if (r === 44 || r === 46) N = true, F++;else {
        if (N) {
          if (L && (h = h * -1, L = false), g) h *= i, o && (x ? Math.abs(c - n - h) > f && (Math.abs(c - h) < f ? o.trace(`Data line ${d}: After a DIFFERENCE the next line should repeat the last value and this does not seem to be the case: Current value: ${h} - Expected: ${c}.`) : Math.abs(c - n - h) > 10 * f ? o.trace(`Data line ${d}: The difference between the first value ${h} and the expected first x value ${c} based on increment after a DIFFERENCE is too high`) : o.trace(`Data line ${d}: The difference between the first value ${h} and the expected first x value ${c} based on increment after a DIFFERENCE is too high`)) : Math.abs(c - h) > f && o.trace(`Data line ${d}: The difference between the first value ${h} and the first x value ${c} is too high`)), g = false, x && (Y = true);else if (Y) Y = false, o && Math.abs(b - h) > s && o.trace(`Data line ${d}: After a duplicate the next line should repeat the same value ${h} !== ${b}`), b = h;else {
            A ? (I = L ? 0 - h : h, x = true, A = false) : S || (X = L ? 0 - h : h);
            let y = S ? h - 1 : 1;
            for (let M = 0; M < y; M++) x ? b += I : b = X, u.x.push(c), u.y.push(b * l), c += n;
          }
          L = false, h = 0, F = 0, N = false, S = false;
        }
        if (r < 74 && r > 63) N = true, x = false, h = r - 64;else if (r > 96 && r < 106) N = true, x = false, h = r - 96, L = true;else if (r === 115) N = true, S = true, h = 9;else if (r > 82 && r < 91) N = true, S = true, h = r - 82;else if (r > 73 && r < 83) N = true, A = true, h = r - 73;else if (r > 105 && r < 115) N = true, A = true, h = r - 105, L = true;else if (r === 36 && m.codePointAt(a + 1) === 36) N = true, C = true;else if (r === 37) N = true, A = true, h = 0, L = false;else if (r === 45) {
          let y = m.codePointAt(a + 1);
          (y !== void 0 && y >= 48 && y <= 57 || y === 44 || y === 46) && (N = true, g || (x = false), L = true);
        } else (r === 13 || r === 10) && (g = true, C = false, d++);
      }
      o && x && o.warn("The last value is a difference, it should be repeated on the next line");
    }
    var oe = /[,\t ]+/;
    function w(e, m, t) {
      if (e.isPeaktable = true, !e.variables || Object.keys(e.variables).length === 2 ? ce(e, m, t) : ue(e, m, t), e.variables) for (let o in e.variables) e.variables[o].data = e.data?.[o];
    }
    function ce(e, m, t) {
      let {
          logger: o
        } = t,
        l = {
          x: [],
          y: []
        };
      e.data = l;
      let i = m.split(/,? *,?[;\r\n]+ */);
      for (let n = 1; n < i.length; n++) {
        let f = i[n].trim().replace($, "").split(oe);
        if (f.length % 2 === 0) for (let s = 0; s < f.length; s = s + 2) e.xFactor !== void 0 && e.yFactor !== void 0 && (l.x.push(Number(f[s]) * e.xFactor), l.y.push(Number(f[s + 1]) * e.yFactor));else o?.warn(`Format error: ${f.toString()}`);
      }
    }
    function ue(e, m, t) {
      let {
          logger: o
        } = t,
        l = {},
        i = Object.keys(e.variables),
        n = i.length;
      for (let s of i) l[s] = [];
      e.data = l;
      let f = m.split(/,? *,?[;\r\n]+ */);
      for (let s = 1; s < f.length; s++) {
        let u = f[s].trim().replace($, "").split(oe);
        if (u.length % n === 0) for (let c = 0; c < u.length; c++) l[i[c % n]].push(Number(u[c]));else o?.warn(`Wrong number of columns: ${u.toString()}`);
      }
    }
    function B(e, m) {
      e.isXYAdata = true;
      let t = {};
      e.data = t;
      let o = m.split(/\r?\n/),
        l = o[0].replace(/^.*?([A-Z]+).*$/, "$1").split("").map(i => i.toLowerCase());
      for (let i = 1; i < o.length; i++) {
        let n = o[i].replace(/^\((.*)\)$/, "$1").split(/ *, */);
        for (let f = 0; f < l.length; f++) {
          let s = n[f];
          switch (l[f]) {
            case "x":
            case "y":
            case "w":
              s = Number.parseFloat(s);
              break;
            case "a":
              s = s.replace(/^<(.*)>$/, "$1");
              break;
            case "m":
              break;
            default:
              continue;
          }
          t[l[f]] || (t[l[f]] = []), t[l[f]].push(s);
        }
      }
    }
    function se(e) {
      return Array.isArray(e) ? e[0] : e;
    }
    function Z(e) {
      let {
          spectra: m
        } = e,
        t = m[0].data.y[0],
        o = t,
        l = m.length,
        i = m[0].data.x.length || 0,
        n = new Array(l);
      for (let r = 0; r < l; r++) {
        n[r] = m[r].data.y;
        for (let a = 0; a < i; a++) {
          let d = n[r][a];
          d < t && (t = d), d > o && (o = d);
        }
      }
      let f = m[0].data.x[0],
        s = m[0].data.x.at(-1),
        {
          firstY: u,
          lastY: c
        } = pe(e);
      if (f > s) for (let r of n) r.reverse();
      u > c && n.reverse();
      let b = [];
      for (let r of n) {
        let a = Float64Array.from(r);
        for (let d = 0; d < a.length; d++) a[d] < 0 && (a[d] = -a[d]);
        b.push(median(a));
      }
      let p = median(b);
      return {
        z: n,
        minX: Math.min(f, s),
        maxX: Math.max(f, s),
        minY: Math.min(u, c),
        maxY: Math.max(u, c),
        minZ: t,
        maxZ: o,
        noise: p
      };
    }
    function pe(e) {
      let {
        spectra: m,
        ntuples: t,
        info: o
      } = e;
      if (t) for (let l of t) {
        let {
          symbol: i,
          nucleus: n,
          units: f
        } = l;
        if (i.match(/[F|T]1/) && f?.toUpperCase().match("HZ")) {
          let s = se(o[".OBSERVEFREQUENCY"]),
            {
              nucleus: u
            } = t.find(d => d.symbol.match(/[F|T]2/));
          if ([s, u, n].some(d => !d)) break;
          let c = getGyromagneticRatio(u),
            b = getGyromagneticRatio(n),
            {
              first: p,
              last: r
            } = l,
            a = b !== null && c !== null ? s * b / c : s;
          return {
            firstY: p / a,
            lastY: r / a
          };
        }
      }
      return {
        firstY: m[0].pageValue,
        lastY: m.at(-1).pageValue
      };
    }
    function H(e, m) {
      let t = e.noise,
        o = e.z,
        l,
        i,
        n,
        f,
        s,
        u,
        c,
        b,
        p = o.length,
        r = o[0].length,
        a,
        d,
        g,
        A,
        x = e.minX,
        S = (e.maxX - x) / (r - 1),
        C = e.minY,
        X = (e.maxY - C) / (p - 1),
        L = e.minZ,
        N = e.maxZ,
        Y = m.nbContourLevels * 2,
        F = new Array(Y),
        y;
      for (let M = 0; M < Y; M++) {
        let U = {};
        F[M] = U;
        let fe = M % 2,
          Q = (N - m.noiseMultiplier * t) * Math.exp((M >> 1) - m.nbContourLevels);
        fe === 0 ? y = Q + m.noiseMultiplier * t : y = 0 - Q - m.noiseMultiplier * t;
        let D = [];
        if (U.zValue = y, U.lines = D, !(y <= L || y >= N)) for (let v = 0; v < p - 1; v++) {
          let _ = o[v],
            ee = o[v + 1];
          for (let T = 0; T < r - 1; T++) l = _[T], i = _[T + 1], n = ee[T], f = ee[T + 1], s = l > y, u = i > y, c = n > y, b = f > y, s !== u && s !== c && (a = T + (y - l) / (i - l), d = v, g = T, A = v + (y - l) / (n - l), D.push(a * S + x, d * X + C, g * S + x, A * X + C)), b !== u && b !== c && (a = T + 1, d = v + 1 - (y - f) / (i - f), g = T + 1 - (y - f) / (n - f), A = v + 1, D.push(a * S + x, d * X + C, g * S + x, A * X + C)), u !== c && (a = (T + 1 - (y - i) / (n - i)) * S + x, d = (v + (y - i) / (n - i)) * X + C, u !== s && (g = T + 1 - (y - i) / (l - i), A = v, D.push(a, d, g * S + x, A * X + C)), c !== s && (g = T, A = v + 1 - (y - n) / (l - n), D.push(a, d, g * S + x, A * X + C)), u !== b && (g = T + 1, A = v + (y - i) / (f - i), D.push(a, d, g * S + x, A * X + C)), c !== b && (g = T + (y - n) / (f - n), A = v + 1, D.push(a, d, g * S + x, A * X + C)));
        }
      }
      return {
        minX: e.minX,
        maxX: e.maxX,
        minY: e.minY,
        maxY: e.maxY,
        segments: F
      };
    }
    function G(e, m) {
      let t = Z(e);
      m.noContour || (e.contourLines = H(t, m), delete t.z), e.minMax = t;
    }
    function z(e, m) {
      for (let t of e) {
        let o = 0,
          l = 0;
        for (let i of t.spectra) {
          if (t.ntuples?.symbol ? (!o && i.observeFrequency && (o = i.observeFrequency), !l && i.shiftOffsetVal && (l = i.shiftOffsetVal)) : (o = i.observeFrequency, l = i.shiftOffsetVal), o && i.xUnits?.toUpperCase().includes("HZ") && (i.xUnits = "PPM", i.xFactor = i.xFactor !== void 0 ? i.xFactor / o : void 0, i.firstX = i.firstX !== void 0 ? i.firstX / o : void 0, i.lastX = i.lastX !== void 0 ? i.lastX / o : void 0, i.deltaX = i.deltaX !== void 0 ? i.deltaX / o : void 0, i.data)) for (let n = 0; n < i.data.x.length; n++) i.data.x[n] /= o;
          if (l && i.xUnits.toLowerCase().includes("ppm") && i.firstX !== void 0 && i.lastX !== void 0) {
            let n = i.firstX - l;
            if (i.firstX = i.firstX - n, i.lastX = i.lastX - n, i.data) for (let f = 0; f < i.data.x.length; f++) i.data.x[f] -= n;
          }
          if (t.ntuples?.nucleus && t.ntuples.symbol) for (let n = 0; n < t.ntuples.nucleus.length; n++) {
            let f = t.ntuples.symbol[n],
              s = t.ntuples.nucleus[n];
            if (f.match(/^[F|T]/) && !s) {
              if (f.match(/[F|T]1/)) if (t.tmp.$NUC2 && typeof t.tmp.$NUC2 == "string") t.ntuples.nucleus[n] = t.tmp.$NUC2;else {
                let u = t.ntuples.symbol.indexOf(f.replace(/^([F|T]).*/, "$12"));
                u && t.ntuples.nucleus[u] && (t.ntuples.nucleus[n] = t.ntuples.nucleus[u]);
              }
              f.match(/[F|T]2/) && typeof t.tmp.$NUC1 == "string" && (t.ntuples.nucleus[n] = t.tmp.$NUC1);
            }
            f.match(/[F|T]2/) && (t.yType = t.ntuples.nucleus[0], t.xType && !getGyromagneticRatio(t.xType) && (t.xType = t.ntuples.nucleus[1]));
          }
          if (o && t.ntuples?.symbol && t.ntuples.nucleus) {
            let n = "",
              f = t.ntuples.symbol.indexOf(i.pageSymbol);
            t.ntuples.units?.[f] && (n = t.ntuples.units[f]);
            let {
              nucleus: s
            } = t.ntuples;
            if (!n.toLowerCase().match(/(ppm|seconds)/) && s.length > 1) {
              if (f !== 0) {
                let p = "Not sure about this ntuples format";
                if (m) {
                  m.warn(p);
                  continue;
                } else throw new Error(p);
              }
              let {
                  nucleus: u
                } = t.ntuples,
                c = getGyromagneticRatio(u[0]),
                b = getGyromagneticRatio(u[1]);
              if (!c || !b) {
                let p = `Problem with determination of gyromagnetic ratio for ${u.join("-")}`;
                if (m) m.error(p);else throw new Error(p);
              } else {
                let p = c / b * o;
                i.pageValue /= p;
              }
            }
          }
        }
      }
    }
    function J(e) {
      let m = e.spectra[0].data;
      e.chromatogram = {
        times: m.x.slice(),
        series: {
          intensity: {
            dimension: 1,
            data: m.y.slice()
          }
        }
      };
    }
    function q(e, m, t) {
      z(e, t.logger), de(e, t);
      for (let o of e) {
        if (Object.keys(o.ntuples).length > 0) {
          let l = [],
            i = Object.keys(o.ntuples);
          for (let n of i) {
            let f = o.ntuples[n];
            if (f) for (let s = 0; s < f.length; s++) l[s] || (l[s] = {}), l[s][n] = f[s];
          }
          o.ntuples = l;
        }
        o.twoD && t.wantXY && (G(o, t), t.logger?.trace({
          profiling: true
        }, "Finished countour plot calculation"), t.keepSpectra || delete o.spectra), t.chromatogram && (o.spectra.length > 1 ? ne(o) : J(o), t.logger?.trace({
          profiling: true
        }, "Finished chromatogram calculation")), delete o.tmp;
      }
    }
    function de(e, m) {
      for (let t of e) for (let o in t.meta) {
        let l = t.meta[o];
        if (typeof l == "string") {
          if (l.startsWith("{")) {
            if (!l.includes(":") && l.endsWith("}")) {
              let i = l.slice(1, -1).split(/[,; ]+/).filter(Boolean);
              for (let n = 0; n < i.length; n++) t.meta[o + String(n)] = m.dynamicTyping ? parseString(i[n]) : i[n];
            }
          } else if (l.startsWith("(")) {
            let i = l.split(/\r?\n/),
              n = /^\((?<from>\d+)\.\.(?<to>\d+)\).*$/;
            if (n.test(i[0])) {
              let [f, s] = i[0].match(n)?.slice(1).map(Number) ?? [],
                u = i.slice(1).join(" ").split(/[,; ]+/).filter(Boolean);
              for (let c = f; c <= s; c++) m.dynamicTyping && typeof u[c - f] == "string" ? t.meta[o + String(c)] = parseString(u[c - f]) : t.meta[o + String(c)] = u[c - f];
            }
          }
        }
      }
    }
    function K(e, m, t) {
      let o = -1,
        l = -1,
        i = "",
        n = "";
      if (t.indexOf("++") > 0) i = t.replace(/.*\(([a-zA-Z0-9]+)\+\+.*/, "$1"), n = t.replace(/.*\.\.([a-zA-Z0-9]+).*/, "$1");else {
        t = t.replaceAll(/[^a-zA-Z%]/g, ""), i = t.charAt(0), n = t.charAt(1), m.variables = {};
        for (let f of t) {
          let s = f.toLowerCase(),
            u = e.ntuples.symbol?.indexOf(f) || 0;
          if (u === -1) throw new Error(`Symbol undefined: ${f}`);
          m.variables[s] = {};
          for (let c in e.ntuples) e.ntuples[c]?.[u] && (m.variables[s][c.replace(/^var/, "")] = e.ntuples[c]?.[u]);
        }
      }
      o = e.ntuples.symbol?.indexOf(i) ?? -1, l = e.ntuples.symbol?.indexOf(n) ?? -1, o === -1 && (o = 0), l === -1 && (l = 0), e.ntuples.first && (e.ntuples.first.length > o && (m.firstX = e.ntuples.first[o]), e.ntuples.first.length > l && (m.firstY = e.ntuples.first[l])), e.ntuples.last && (e.ntuples.last.length > o && (m.lastX = e.ntuples.last[o]), e.ntuples.last.length > l && (m.lastY = e.ntuples.last[l])), e.ntuples.vardim && e.ntuples.vardim.length > o && (m.nbPoints = e.ntuples.vardim[o]), e.ntuples.factor && (e.ntuples.factor.length > o && (m.xFactor = e.ntuples.factor[o]), e.ntuples.factor.length > l && (m.yFactor = e.ntuples.factor[l])), e.ntuples.units && (e.ntuples.units.length > o && (e.ntuples.varname?.[o] ? m.xUnits = `${e.ntuples.varname[o]} [${e.ntuples.units[o]}]` : m.xUnits = e.ntuples.units[o]), e.ntuples.units.length > l && (e.ntuples.varname?.[l] ? m.yUnits = `${e.ntuples.varname[l]} [${e.ntuples.units[l]}]` : m.yUnits = e.ntuples.units[l]));
    }
    function j(e) {
      e.xFactor || (e.xFactor = 1), e.yFactor || (e.yFactor = 1);
    }
    var R = /[ \t]*,[ \t]*/,
      he = {
        removeComments: false,
        keepRecordsRegExp: /^$/,
        canonicDataLabels: true,
        canonicMetadataLabels: false,
        dynamicTyping: true,
        withoutXY: false,
        noTrimRegExp: /^$/,
        chromatogram: false,
        keepSpectra: false,
        noContour: false,
        nbContourLevels: 7,
        noiseMultiplier: 5
      };
    function pt(e, m = {}) {
      e = ensureString(e);
      let t = {
        ...he,
        ...m
      };
      t.logger?.debug("Starting jcamp conversion"), t.wantXY = !t.withoutXY, t.start = Date.now();
      let o = [],
        l = {
          entries: [],
          flatten: []
        },
        i = {
          children: [],
          spectra: [],
          ntuples: {},
          info: {},
          meta: {},
          tmp: {}
        },
        n = i,
        f = [],
        s = {
          data: {}
        };
      t.logger?.trace({
        profiling: true
      }, "Before split to LDRS");
      let u = e.replaceAll(/[\r\n]+##/g, `
##`).split(`
##`);
      t.logger?.trace({
        profiling: true
      }, "Split to LDRS"), u[0] && (u[0] = u[0].replace(/^[\r\n ]*##/, ""));
      for (let c of u) {
        let b = c.indexOf("="),
          p = b > 0 ? c.slice(0, Math.max(0, b)) : c,
          r = b > 0 ? p.match(t.noTrimRegExp) ? c.slice(Math.max(0, b + 1)) : c.slice(Math.max(0, b + 1)).trim() : "",
          a = p.replaceAll(/[_ -]/g, "").toUpperCase();
        if (a === "DATATABLE") {
          let d = r.indexOf(`
`);
          if (d === -1 && (d = r.indexOf("\r")), d > 0) {
            let g = r.slice(0, Math.max(0, d)).split(/[ ,;\t]+/);
            K(n, s, g[0]), s.datatable = g[0], g[1]?.includes("PEAKS") ? a = "PEAKTABLE" : g[1] && (g[1].indexOf("XYDATA") || g[0].indexOf("++") > 0) && (a = "XYDATA", s.nbPoints && s.lastX !== void 0 && s.firstX !== void 0 && (s.deltaX = (s.lastX - s.firstX) / (s.nbPoints - 1)));
          }
        }
        if (a === "XYDATA") {
          t.wantXY && (j(s), r.match(/.*\+\+.*/) ? (s.nbPoints && s.lastX !== void 0 && s.firstX !== void 0 && (s.deltaX = (s.lastX - s.firstX) / (s.nbPoints - 1)), V(s, r, t)) : w(s, r, t), n?.spectra.push(s), s = {
            data: {}
          });
          continue;
        } else if (a === "PEAKTABLE") {
          t.wantXY && (j(s), w(s, r, t), n?.spectra.push(s), s = {
            data: {}
          });
          continue;
        }
        if (a === "PEAKASSIGNMENTS") {
          t.wantXY && (r.match(/.*[^A-Z]*.*/) && B(s, r), n?.spectra.push(s), s = {
            data: {}
          });
          continue;
        }
        if (t.removeComments && (r = r.split(/\r?\n/).map(d => d.replace(/ *\$\$.*$/, "")).join(`
`)), a === "TITLE") {
          let d = n;
          d.children || (d.children = []), n = {
            spectra: [],
            ntuples: {},
            info: {},
            meta: {},
            tmp: {}
          }, d.children.push(n), f.push(d), o.push(n), n.title = r;
        } else a === "DATATYPE" ? (n.dataType = r, r.match(/^nd|\snd\s/i) && (n.twoD = true)) : a === "NTUPLES" ? r.match(/^nd|\snd\s/i) && (n.twoD = true) : a === "DATACLASS" ? n.dataClass = r : a === "JCAMPDX" ? n.jcampDX = E(r) : a === "JCAMPCS" ? n.jcampCS = E(r) : a === "XUNITS" ? s.xUnits = r : a === "YUNITS" ? s.yUnits = r : a === "FIRSTX" ? s.firstX = Number(r) : a === "LASTX" ? s.lastX = Number(r) : a === "FIRSTY" ? s.firstY = Number(r) : a === "LASTY" ? s.lastY = Number(r) : a === "NPOINTS" ? s.nbPoints = Number(r) : a === "XFACTOR" ? s.xFactor = Number(r) : a === "YFACTOR" ? s.yFactor = Number(r) : a === "MAXX" ? s.maxX = Number(r) : a === "MINX" ? s.minX = Number(r) : a === "MAXY" ? s.maxY = Number(r) : a === "MINY" ? s.minY = Number(r) : a === "DELTAX" ? s.deltaX = Number(r) : a === ".OBSERVEFREQUENCY" || a === "$SFO1" ? s.observeFrequency || (s.observeFrequency = Number(r)) : a === ".OBSERVENUCLEUS" ? s.xType || (n.xType = r.replaceAll(/[^a-zA-Z0-9]/g, "")) : a === "$OFFSET" ? (n.shiftOffsetNum = 0, s.shiftOffsetVal || (s.shiftOffsetVal = Number(r))) : a === "$REFERENCEPOINT" || (a === "VARNAME" ? n.ntuples.varname = r.split(R) : a === "SYMBOL" ? n.ntuples.symbol = r.split(R) : a === "VARTYPE" ? n.ntuples.vartype = r.split(R) : a === "VARFORM" ? n.ntuples.varform = r.split(R) : a === "VARDIM" ? n.ntuples.vardim = O(r.split(R)) : a === "UNITS" ? n.ntuples.units = r.split(R) : a === "FACTOR" ? n.ntuples.factor = O(r.split(R)) : a === "FIRST" ? n.ntuples.first = O(r.split(R)) : a === "LAST" ? n.ntuples.last = O(r.split(R)) : a === "MIN" ? n.ntuples.min = O(r.split(R)) : a === "MAX" ? n.ntuples.max = O(r.split(R)) : a === ".NUCLEUS" ? n.ntuples && (n.ntuples.nucleus = r.split(R).map(d => d.replaceAll(/[^a-zA-Z0-9]/g, ""))) : a === "PAGE" ? (s.page = r.trim(), s.pageValue = Number(r.replace(/^.*=/, "")), s.pageSymbol = s.page.replace(/[=].*/, "")) : a === "RETENTIONTIME" ? s.pageValue = Number(r) : re(a) ? s[k$1(a)] = r : a === "SAMPLEDESCRIPTION" ? s.sampleDescription = r : a.startsWith("$NUC") ? !n.tmp[a] && !r.includes("off") && (n.tmp[a] = r.replaceAll(/[<>]/g, "")) : a === "END" && (n = f.pop()));
        if (n?.info && n.meta && a.match(t.keepRecordsRegExp)) {
          let d, g;
          p.startsWith("$") ? (g = t.canonicMetadataLabels ? a.slice(1) : p.slice(1), d = n.meta) : (g = t.canonicDataLabels ? a : p, d = n.info), t.dynamicTyping && (r = parseString(r)), d[g] ? (Array.isArray(d[g]) || (d[g] = [d[g]]), d[g].push(r)) : d[g] = r;
        }
      }
      if (t.logger?.trace({
        profiling: true
      }, "Finished parsing"), q(o, l, t), t.logger?.trace({
        profiling: true
      }, "Total time"), l.entries = i.children || [], l.flatten = o, t.logger) {
        t.logger.debug("Finished jcamp conversion");
        for (let c of l.flatten) t.logger.debug(`${c.dataType} - ${c.title}`);
      }
      return l;
    }

    /**
     * Creates a new Analysis from a JCAMP string
     * @param jcamp - String containing the JCAMP data
     * @param [options={}]
     * @param [options.id=Math.random()]
     * @param [options.label=options.id] - human redeable label
     * @param [options.spectrumCallback] - a callback to apply on variables when creating spectrum
     * @returns - New class element with the given data
     */
    function fromJcamp(jcamp, options = {}) {
      const analysis = new Analysis(options);
      addJcamp(analysis, jcamp);
      return analysis;
    }
    function addJcamp(analysis, jcamp) {
      const converted = pt(jcamp, {
        keepRecordsRegExp: /.*/
      });
      for (const entry of converted.flatten) {
        if (!entry.spectra?.[0]) continue;
        const currentSpectrum = entry.spectra[0];
        // we ensure variables
        if (!currentSpectrum.variables) {
          const variables = {};
          currentSpectrum.variables = variables;
          variables.x = {
            label: currentSpectrum.xUnits,
            symbol: 'X',
            data: currentSpectrum.data.x || currentSpectrum.data.X
          };
          variables.y = {
            label: currentSpectrum.yUnits,
            symbol: 'Y',
            data: currentSpectrum.data.y || currentSpectrum.data.Y
          };
        } else {
          for (const key in currentSpectrum.variables) {
            const variable = currentSpectrum.variables[key];
            if (variable.label) continue;
            variable.label = variable.name || variable.symbol || key;
            if (variable.units && !variable.label.includes(variable.units)) {
              // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
              variable.label += ` [${variable.units}]`;
            }
          }
        }
        analysis.pushSpectrum(currentSpectrum.variables, {
          dataType: entry.dataType,
          title: entry.title,
          meta: entry.meta
        });
      }
    }

    const addInfoData = (data, options = {}) => {
      const {
        keys = Object.keys(data),
        prefix = '##$'
      } = options;
      let header = '';
      for (const key of keys) {
        header += typeof data[key] === 'object' ? `${prefix}${key}=${JSON.stringify(data[key])}\n` : `${prefix}${key}=${data[key]}\n`;
      }
      return header;
    };

    function checkMatrix(data) {
      if (!isAnyArray$1(data) || !isAnyArray$1(data[0])) {
        throw new Error(`2D data should be a matrix`);
      }
    }

    function checkNumberOrArray(data) {
      if (!isAnyArray$1(data) || isAnyArray$1(data[0])) {
        throw new Error(`x and y data should be an array of numbers`);
      }
    }

    function getExtremeValues(data) {
      if (isAnyArray$1(data[0])) {
        checkMatrix(data);
        const firstRow = data[0];
        return {
          firstLast: {
            first: firstRow[0],
            last: data[data.length - 1][data[0].length - 1]
          },
          minMax: matrixMinMaxZ(data)
        };
      }
      checkNumberOrArray(data);
      return {
        firstLast: {
          first: data[0],
          last: data[data.length - 1]
        },
        minMax: xMinMaxValues(data)
      };
    }

    /**
     * Parse from a xyxy data array
     * @param variables - Variables to convert to jcamp
     * @param [options={}] - options that allows to add meta data in the jcamp
     * @return JCAMP-DX text file corresponding to the variables
     */
    function creatorNtuples(variables, options) {
      const {
        meta = {},
        info = {}
      } = options;
      const {
        title = '',
        owner = '',
        origin = '',
        dataType = '',
        ...resInfo
      } = info;
      const symbol = [];
      const varName = [];
      const varType = [];
      const varDim = [];
      const units = [];
      const first = [];
      const last = [];
      const min = [];
      const max = [];
      const keys = Object.keys(variables);
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i];
        const variable = variables[key];
        if (!variable) continue;
        const name = variable?.label.replace(/ *\[.*/, '');
        const unit = variable?.label.replace(/.*\[(?<units>.*)\].*/, '$<units>');
        const {
          firstLast,
          minMax
        } = getExtremeValues(variable.data);
        symbol.push(variable.symbol || key);
        varName.push(name || key);
        varDim.push(variable.data.length);
        first.push(firstLast.first);
        last.push(firstLast.last);
        max.push(minMax.max);
        min.push(minMax.min);
        if (variable.isDependent !== undefined) {
          varType.push(variable.isDependent ? 'DEPENDENT' : 'INDEPENDENT');
        } else {
          varType.push(variable.isDependent !== undefined ? !variable.isDependent : i === 0 ? 'INDEPENDENT' : 'DEPENDENT');
        }
        units.push(variable.units || unit || '');
      }
      let header = `##TITLE=${title}
##JCAMP-DX=6.00
##DATA TYPE=${dataType}
##DATA CLASS= NTUPLES
##ORIGIN=${origin}
##OWNER=${owner}\n`;
      header += addInfoData(resInfo, {
        prefix: '##'
      });
      header += addInfoData(meta);
      header += `##NTUPLES= ${dataType}
##VAR_NAME=  ${varName.join()}
##SYMBOL=    ${symbol.join()}
##VAR_TYPE=  ${varType.join()}
##VAR_DIM=   ${varDim.join()}
##UNITS=     ${units.join()}
##FIRST=     ${first.join()}
##LAST=      ${last.join()}
##MIN=       ${min.join()}
##MAX=       ${max.join()}
##PAGE= N=1\n`;
      header += `##DATA TABLE= (${symbol.join('')}..${symbol.join('')}), PEAKS\n`;
      for (let i = 0; i < variables.x.data.length; i++) {
        const point = [];
        for (const key of keys) {
          const variable = variables[key];
          if (!variable) continue;
          point.push(variable.data[i]);
        }
        header += `${point.join('\t')}\n`;
      }
      header += `##END NTUPLES= ${dataType}\n`;
      header += '##END=\n##END=';
      return header;
    }

    function getFactorNumber(minMax, maxValue = 2 ** 31 - 1) {
      let factor;
      if (minMax.min < 0) {
        if (minMax.max > 0) {
          factor = Math.max(-minMax.min, minMax.max) / maxValue;
        } else {
          factor = -minMax.min / maxValue;
        }
      } else {
        factor = minMax.max / maxValue;
      }
      return factor;
    }

    function getBestFactor(array, options = {}) {
      const {
        maxValue,
        factor,
        minMax
      } = options;
      if (factor !== undefined) {
        return factor;
      }
      // is there non integer number ?
      let onlyInteger = true;
      for (const y of array) {
        if (Math.round(y) !== y) {
          onlyInteger = false;
          break;
        }
      }
      if (onlyInteger) {
        return 1;
      }
      // we need to rescale the values
      // need to find the max and min values
      const extremeValues = minMax || xMinMaxValues(array);
      return getFactorNumber(extremeValues, maxValue);
    }

    /**
     * Reconvert number to original value
     * @param number Number used for computation
     * @param factor Multiplying factor
     * @returns Original value
     */
    function getNumber(number, factor) {
      if (factor !== 1) number /= factor;
      const rounded = Math.round(number);
      if (rounded !== number && Math.abs(rounded - number) <= Number.EPSILON) {
        return rounded;
      }
      return number;
    }

    function peakTableCreator(data, options = {}) {
      const {
        xFactor = 1,
        yFactor = 1
      } = options.info || {};
      let firstX = Number.POSITIVE_INFINITY;
      let lastX = Number.NEGATIVE_INFINITY;
      let firstY = Number.POSITIVE_INFINITY;
      let lastY = Number.NEGATIVE_INFINITY;
      const lines = [];
      for (let i = 0; i < data.x.length; i++) {
        const x = data.x[i];
        const y = data.y[i];
        if (firstX > x) {
          firstX = x;
        }
        if (lastX < x) {
          lastX = x;
        }
        if (firstY > y) {
          firstY = y;
        }
        if (lastY < y) {
          lastY = y;
        }
      }
      lines.push(`##FIRSTX=${firstX}`);
      lines.push(`##LASTX=${lastX}`);
      lines.push(`##FIRSTY=${firstY}`);
      lines.push(`##LASTY=${lastY}`);
      lines.push(`##XFACTOR=${xFactor}`);
      lines.push(`##YFACTOR=${yFactor}`);
      lines.push('##PEAK TABLE=(XY..XY)');
      for (let i = 0; i < data.x.length; i++) {
        lines.push(`${getNumber(data.x[i], xFactor)} ${getNumber(data.y[i], yFactor)}`);
      }
      return lines;
    }

    function rescaleAndEnsureInteger(data, factor = 1) {
      if (factor === 1) return data.map(value => Math.round(value));
      return xDivide(data, factor).map(value => Math.round(value));
    }

    /**
     * class encodes a integer vector as a String in order to store it in a text file.
     * The algorithms used to encode the data are describe in:
     *            http://www.iupac.org/publications/pac/pdf/2001/pdf/7311x1765.pdf
     */
    const newLine = '\n';
    const pseudoDigits = [['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], ['@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], ['@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], ['%', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R'], ['%', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r'], [' ', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 's']];
    const SQZ_P = 1;
    const SQZ_N = 2;
    const DIF_P = 3;
    const DIF_N = 4;
    const DUP = 5;
    const maxLinelength = 100;
    /**
     * This function encodes the given vector. The xyEncoding format is specified by the
     * xyEncoding option
     * @param xyEncoding: ('FIX','SQZ','DIF','DIFDUP','CVS','PAC') Default 'DIFDUP'
     * @return {string}
     */
    function vectorEncoder(data, firstX, intervalX, xyEncoding) {
      switch (xyEncoding) {
        case 'FIX':
          return fixEncoding(data, firstX, intervalX);
        case 'SQZ':
          return squeezedEncoding(data, firstX, intervalX);
        case 'DIF':
          return differenceEncoding(data, firstX, intervalX);
        case 'DIFDUP':
          return differenceDuplicateEncoding(data, firstX, intervalX);
        case 'CSV':
          return commaSeparatedValuesEncoding(data, firstX, intervalX);
        case 'PAC':
          return packedEncoding(data, firstX, intervalX);
        default:
          return differenceEncoding(data, firstX, intervalX);
      }
    }
    /**
     * @private
     * No data compression used. The data is separated by a comma(',').
     */
    function commaSeparatedValuesEncoding(data, firstX, intervalX) {
      return fixEncoding(data, firstX, intervalX, ',');
    }
    /**
     * @private
     * No data compression used. The data is separated by the specified separator.
     */
    function fixEncoding(data, firstX, intervalX, separator = ' ') {
      let outputData = '';
      let j = 0;
      const dataLength = data.length;
      while (j < dataLength - 7) {
        outputData += String(Math.ceil(firstX + j * intervalX));
        for (let i = 0; i < 8; i++) {
          outputData += `${separator}${data[j++]}`;
        }
        outputData += newLine;
      }
      if (j < dataLength) {
        // We add last numbers
        outputData += String(Math.ceil(firstX + j * intervalX));
        for (let i = j; i < dataLength; i++) {
          outputData += `${separator}${data[i]}`;
        }
      }
      return outputData;
    }
    /**
     * @private
     * No data compression used. The data is separated by the sign of the number.
     */
    function packedEncoding(data, firstX, intervalX) {
      let outputData = '';
      let j = 0;
      const dataLength = data.length;
      while (j < dataLength - 7) {
        outputData += String(Math.ceil(firstX + j * intervalX));
        for (let i = 0; i < 8; i++) {
          outputData += data[j] < 0 ? String(data[j++]) : `+${data[j++]}`;
        }
        outputData += newLine;
      }
      if (j < dataLength) {
        // We add last numbers
        outputData += String(Math.ceil(firstX + j * intervalX));
        for (let i = j; i < dataLength; i++) {
          outputData += data[i] < 0 ? String(data[i]) : `+${data[i]}`;
        }
      }
      return outputData;
    }
    /**
     * @private
     * Data compression is possible using the squeezed form (SQZ) in which the delimiter, the leading digit,
     * and sign are replaced by a pseudo-digit from Table 1. For example, the Y-values 30, 32 would be
     * represented as C0C2.
     */
    function squeezedEncoding(data, firstX, intervalX) {
      let outputData = '';
      // String outputData = new String();
      let j = 0;
      const dataLength = data.length;
      while (j < dataLength - 10) {
        outputData += String(Math.ceil(firstX + j * intervalX));
        for (let i = 0; i < 10; i++) {
          outputData += squeezedDigit(data[j++].toString());
        }
        outputData += newLine;
      }
      if (j < dataLength) {
        // We add last numbers
        outputData += String(Math.ceil(firstX + j * intervalX));
        for (let i = j; i < dataLength; i++) {
          outputData += squeezedDigit(data[i].toString());
        }
      }
      return outputData;
    }
    /**
     * @private
     * Duplicate suppression xyEncoding
     */
    function differenceDuplicateEncoding(data, firstX, intervalX) {
      let mult = 0;
      let index = 0;
      let charCount = 0;
      // We built a string where we store the encoded data.
      let encodedData = '';
      let encodedNumber = '';
      let temp = '';
      // We calculate the differences vector
      const diffData = new Array(data.length - 1);
      for (let i = 0; i < diffData.length; i++) {
        diffData[i] = data[i + 1] - data[i];
      }
      // We simulate a line carry
      const numDiff = diffData.length;
      while (index < numDiff) {
        if (charCount === 0) {
          // Start line
          encodedNumber = `${Math.ceil(firstX + index * intervalX)}${squeezedDigit(data[index].toString())}${differenceDigit(diffData[index].toString())}`;
          encodedData += encodedNumber;
          charCount += encodedNumber.length;
        } else if (diffData[index - 1] === diffData[index]) {
          // Try to insert next difference
          mult++;
        } else if (mult > 0) {
          // Now we know that it can be in line
          mult++;
          encodedNumber = duplicateDigit(mult.toString());
          encodedData += encodedNumber;
          charCount += encodedNumber.length;
          mult = 0;
          index--;
        } else {
          // Check if it fits, otherwise start a new line
          encodedNumber = differenceDigit(diffData[index].toString());
          if (encodedNumber.length + charCount < maxLinelength) {
            encodedData += encodedNumber;
            charCount += encodedNumber.length;
          } else {
            // start a new line
            encodedData += newLine;
            temp = `${Math.ceil(firstX + index * intervalX)}${squeezedDigit(data[index].toString())}${encodedNumber}`;
            encodedData += temp; // Each line start with first index number.
            charCount = temp.length;
          }
        }
        index++;
      }
      if (mult > 0) {
        encodedData += duplicateDigit((mult + 1).toString());
      }
      // We insert the last data from fid. It is done to control of data
      // The last line start with the number of datas in the fid.
      encodedData += `${newLine}${Math.ceil(firstX + index * intervalX)}${squeezedDigit(data[index].toString())}`;
      return encodedData;
    }
    /**
     * @private
     * Differential xyEncoding
     */
    function differenceEncoding(data, firstX, intervalX) {
      let index = 0;
      let charCount = 0;
      let i;
      let encodedData = '';
      let encodedNumber = '';
      let temp = '';
      // We calculate the differences vector
      const diffData = new Array(data.length - 1);
      for (i = 0; i < diffData.length; i++) {
        diffData[i] = data[i + 1] - data[i];
      }
      const numDiff = diffData.length;
      while (index < numDiff) {
        if (charCount === 0) {
          // We convert the first number.
          encodedNumber = `${Math.ceil(firstX + index * intervalX)}${squeezedDigit(data[index].toString())}${differenceDigit(diffData[index].toString())}`;
          encodedData += encodedNumber;
          charCount += encodedNumber.length;
        } else {
          encodedNumber = differenceDigit(diffData[index].toString());
          if (encodedNumber.length + charCount < maxLinelength) {
            encodedData += encodedNumber;
            charCount += encodedNumber.length;
          } else {
            encodedData += newLine;
            temp = `${Math.ceil(firstX + index * intervalX)}${squeezedDigit(data[index].toString())}${encodedNumber}`;
            encodedData += temp; // Each line start with first index number.
            charCount = temp.length;
          }
        }
        index++;
      }
      // We insert the last number from data. It is done to control of data
      encodedData += `${newLine}${Math.ceil(firstX + index * intervalX)}${squeezedDigit(data[index].toString())}`;
      return encodedData;
    }
    /**
     * @private
     * Convert number to the ZQZ format, using pseudo digits.
     */
    function squeezedDigit(num) {
      let sqzDigits = '';
      if (num.startsWith('-')) {
        sqzDigits += pseudoDigits[SQZ_N][num.charCodeAt(1) - 48];
        if (num.length > 2) {
          sqzDigits += num.substring(2);
        }
      } else {
        sqzDigits += pseudoDigits[SQZ_P][num.charCodeAt(0) - 48];
        if (num.length > 1) {
          sqzDigits += num.substring(1);
        }
      }
      return sqzDigits;
    }
    /**
     * Convert number to the DIF format, using pseudo digits.
     */
    function differenceDigit(num) {
      let diffDigits = '';
      if (num.startsWith('-')) {
        diffDigits += pseudoDigits[DIF_N][num.charCodeAt(1) - 48];
        if (num.length > 2) {
          diffDigits += num.substring(2);
        }
      } else {
        diffDigits += pseudoDigits[DIF_P][num.charCodeAt(0) - 48];
        if (num.length > 1) {
          diffDigits += num.substring(1);
        }
      }
      return diffDigits;
    }
    /**
     * Convert number to the DUP format, using pseudo digits.
     */
    function duplicateDigit(num) {
      let dupDigits = '';
      dupDigits += pseudoDigits[DUP][num.charCodeAt(0) - 48];
      if (num.length > 1) {
        dupDigits += num.substring(1);
      }
      return dupDigits;
    }

    function xyDataCreator(data, options = {}) {
      const {
        xyEncoding = 'DIF'
      } = options;
      const {
        xFactor = 1,
        yFactor = 1
      } = options.info || {};
      const firstX = data.x[0];
      const lastX = data.x[data.x.length - 1];
      const firstY = data.y[0];
      const lastY = data.y[data.y.length - 1];
      const nbPoints = data.x.length;
      const deltaX = (lastX - firstX) / (nbPoints - 1);
      const lines = [];
      lines.push(`##FIRSTX=${firstX}`);
      lines.push(`##LASTX=${lastX}`);
      lines.push(`##FIRSTY=${firstY}`);
      lines.push(`##LASTY=${lastY}`);
      lines.push(`##DELTAX=${deltaX}`);
      lines.push(`##XFACTOR=${xFactor}`);
      lines.push(`##YFACTOR=${yFactor}`);
      lines.push('##XYDATA=(X++(Y..Y))');
      const line = vectorEncoder(rescaleAndEnsureInteger(data.y, yFactor), firstX / xFactor, deltaX / xFactor, xyEncoding);
      if (line) lines.push(line);
      return lines;
    }

    /**
     * Create a jcamp
     * @param data object of array
     * @param [options={meta:{},info:{}} - metadata object
     * @returns JCAMP of the input
     */
    function fromJSON(data, options = {}) {
      const {
        meta = {},
        info = {},
        xyEncoding
      } = options;
      const {
        title = '',
        owner = '',
        origin = '',
        dataType = '',
        xUnits = '',
        yUnits = '',
        ...resInfo
      } = info;
      let {
        xFactor,
        yFactor
      } = info;
      data = {
        x: data.x,
        y: data.y
      };
      let header = `##TITLE=${title}
##JCAMP-DX=4.24
##DATA TYPE=${dataType}
##ORIGIN=${origin}
##OWNER=${owner}
##XUNITS=${xUnits}
##YUNITS=${yUnits}\n`;
      header += addInfoData(resInfo, {
        prefix: '##'
      });
      header += addInfoData(meta);
      // we leave the header and utf8 fonts ${header.replace(/[^\t\n\x20-\x7F]/g, '')
      if (xyEncoding) {
        xFactor = getBestFactor(data.x, {
          factor: xFactor
        });
        yFactor = getBestFactor(data.y, {
          factor: yFactor
        });
        return `${header}##NPOINTS=${data.x.length}
${xyDataCreator(data, {
      info: {
        xFactor,
        yFactor
      },
      xyEncoding
    }).join('\n')}
##END=`;
      } else {
        if (xFactor === undefined) xFactor = 1;
        if (yFactor === undefined) yFactor = 1;
        if (xFactor !== 1) {
          //@ts-expect-error xFactor is always defined
          data.x = data.x.map(value => value / xFactor);
        }
        if (yFactor !== 1) {
          //@ts-expect-error yFactor is always defined
          data.y = data.y.map(value => value / yFactor);
        }
        return `${header}##NPOINTS=${data.x.length}
${peakTableCreator(data, {
      info: {
        xFactor,
        yFactor
      }
    }).join('\n')}
##END=`;
      }
    }

    /**
     * Create a jcamp from variables
     */
    function fromVariables(/** object of variables */
    variables, options = {}) {
      const {
        info = {},
        meta = {},
        forceNtuples = false
      } = options;
      const jcampOptions = {
        info,
        meta
      };
      const keys = Object.keys(variables).map(key => key.toLowerCase());
      if (!forceNtuples && keys.length === 2) {
        const x = variables.x;
        const xLabel = x.label || 'x';
        if (variables.x.units) {
          if (xLabel.includes(variables.x.units)) {
            jcampOptions.info.xUnits = xLabel;
          } else {
            jcampOptions.info.xUnits = `${xLabel} (${variables.x.units})`;
          }
        } else {
          jcampOptions.info.xUnits = xLabel;
        }
        const y = variables.y;
        const yLabel = y.label || 'y';
        if (variables.y.units) {
          if (yLabel.includes(variables.y.units)) {
            jcampOptions.info.xUnits = yLabel;
          } else {
            jcampOptions.info.yUnits = `${yLabel} (${variables.y.units})`;
          }
        } else {
          jcampOptions.info.yUnits = yLabel;
        }
        const xData = variables.x.data;
        const yData = variables.y.data;
        checkNumberOrArray(xData);
        checkNumberOrArray(yData);
        return fromJSON({
          x: xData,
          y: yData
        }, jcampOptions);
      } else {
        return creatorNtuples(variables, options);
      }
    }

    function toJcamps(analysis, options = {}) {
      const jcamps = [];
      for (const spectrum of analysis.spectra) {
        jcamps.push(getJcamp(spectrum, options));
      }
      return jcamps;
    }
    function getJcamp(spectrum, options) {
      const {
        info = {},
        meta = {}
      } = options;
      const jcampOptions = {
        info: {
          title: spectrum.title,
          dataType: spectrum.dataType,
          ...info
        },
        meta: {
          ...spectrum.meta,
          ...meta
        }
      };
      return fromVariables(spectrum.variables, jcampOptions);
    }

    function toJcamp(analysis, options = {}) {
      return toJcamps(analysis, options).join('\n');
    }

    function toText(analysis, options = {}) {
      // Export all the data to Csv
      if (!options.selector && !options.normalization) {
        return exportText(analysis.spectra, options);
      }
      // Export selected variables
      const spectra = analysis.getNormalizedSpectra(options);
      // const spectra = analysis.getXYSpectrum(options.selector);
      return exportText(spectra, options);
    }
    function exportText(spectrums, options) {
      const {
        endOfLine = '\n',
        fieldSeparator = ','
      } = options;
      const result = new Array(spectrums.length);
      for (let index = 0; index < spectrums.length; index++) {
        const variables = Object.values(spectrums[index].variables);
        const labels = variables.map(v => v.label);
        const maxNumberData = Math.max(...variables.map(v => v.data.length));
        const lines = [labels.join(fieldSeparator)];
        for (let lineIndex = 0; lineIndex < maxNumberData; lineIndex++) {
          lines.push(variables.map(({
            data
          }) => data[lineIndex] === undefined ? '' : data[lineIndex]).join(fieldSeparator));
        }
        result[index] = lines.join(endOfLine);
      }
      return result;
    }

    /**
     * Generate a jsgraph chart format from an array of Analysis
     * @param analyses
     * @param options
     */
    function toMatrix(analyses, options = {}) {
      const {
        selector = {},
        normalization,
        xLabel = 'x',
        delta = 0,
        endOfLine = '\n'
      } = options;
      const data = [];
      const labels = [xLabel];
      const titles = ['x'];
      for (const analysis of analyses) {
        const spectra = analysis.getNormalizedSpectra({
          selector,
          normalization
        });
        for (const spectrum of spectra) {
          titles.push(spectrum.title || '');
          labels.push(analysis.label || '');
          data.push({
            x: spectrum.variables.x.data,
            y: spectrum.variables.y.data
          });
        }
      }
      const aligned = xyArrayAlign(data, {
        delta
      });
      const lines = [labels.join('\t'), titles.join('\t')];
      for (let row = 0; row < aligned.x.length; row++) {
        const line = [aligned.x[row]];
        for (const column of aligned.ys) {
          line.push(column[row]);
        }
        lines.push(line.join('\t'));
      }
      const text = lines.join(endOfLine);
      return text;
    }
    // need to find all the unique Xs

    const JSGraph = {
      getJSGraph,
      getNormalizationAnnotations
    };

    /* @preserve
    **
    ** LICENSE for the sqlite3 WebAssembly/JavaScript APIs.
    **
    ** This bundle (typically released as sqlite3.js or sqlite3.mjs)
    ** is an amalgamation of JavaScript source code from two projects:
    **
    ** 1) https://emscripten.org: the Emscripten "glue code" is covered by
    **    the terms of the MIT license and University of Illinois/NCSA
    **    Open Source License, as described at:
    **
    **    https://emscripten.org/docs/introducing_emscripten/emscripten_license.html
    **
    ** 2) https://sqlite.org: all code and documentation labeled as being
    **    from this source are released under the same terms as the sqlite3
    **    C library:
    **
    ** 2022-10-16
    **
    ** The author disclaims copyright to this source code.  In place of a
    ** legal notice, here is a blessing:
    **
    ** *   May you do good and not evil.
    ** *   May you find forgiveness for yourself and forgive others.
    ** *   May you share freely, never taking more than you give.
    */
    /* @preserve
    ** This code was built from sqlite3 version...
    **
    ** SQLITE_VERSION "3.52.0"
    ** SQLITE_VERSION_NUMBER 3052000
    ** SQLITE_SOURCE_ID "2026-01-30 06:37:34 407724c4e80efdf93d885e95b5209a100a3f470fe0298138be57201f65f9817e"
    **
    ** Emscripten SDK: 5.0.0
    */
    async function sqlite3InitModule(moduleArg = {}) {
      var moduleRtn;
      var Module = moduleArg;
      var ENVIRONMENT_IS_WEB = !!globalThis.window;
      var ENVIRONMENT_IS_WORKER = !!globalThis.WorkerGlobalScope;
      globalThis.process?.versions?.node && globalThis.process?.type;
      var thisProgram = "./this.program";
      var _scriptName = (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('dls-analysis.umd.js', document.baseURI).href));
      var scriptDirectory = "";
      function locateFile(path) {
        if (Module["locateFile"]) return Module["locateFile"](path, scriptDirectory);
        return scriptDirectory + path;
      }
      var readAsync, readBinary;
      if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
        try {
          scriptDirectory = new URL(".", _scriptName).href;
        } catch {}
        if (ENVIRONMENT_IS_WORKER) readBinary = url => {
          var xhr = new XMLHttpRequest();
          xhr.open("GET", url, false);
          xhr.responseType = "arraybuffer";
          xhr.send(null);
          return new Uint8Array(xhr.response);
        };
        readAsync = async url => {
          var response = await fetch(url, {
            credentials: "same-origin"
          });
          if (response.ok) return response.arrayBuffer();
          throw new Error(response.status + " : " + response.url);
        };
      }
      var out = console.log.bind(console);
      var err = console.error.bind(console);
      var wasmBinary;
      var ABORT = false,
        readyPromiseResolve,
        readyPromiseReject,
        HEAP8,
        HEAPU8,
        HEAP16,
        HEAP32,
        HEAPU32,
        HEAP64;
      var runtimeInitialized = false;
      function updateMemoryViews() {
        var b = wasmMemory.buffer;
        HEAP8 = new Int8Array(b);
        HEAP16 = new Int16Array(b);
        HEAPU8 = new Uint8Array(b);
        HEAP32 = new Int32Array(b);
        HEAPU32 = new Uint32Array(b);
        HEAP64 = new BigInt64Array(b);
        new BigUint64Array(b);
      }
      function initMemory() {
        if (Module["wasmMemory"]) wasmMemory = Module["wasmMemory"];else {
          var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 8388608;
          wasmMemory = new WebAssembly.Memory({
            "initial": INITIAL_MEMORY / 65536,
            "maximum": 32768
          });
        }
        updateMemoryViews();
      }
      function preRun() {
        if (Module["preRun"]) {
          if (typeof Module["preRun"] == "function") Module["preRun"] = [Module["preRun"]];
          while (Module["preRun"].length) addOnPreRun(Module["preRun"].shift());
        }
        callRuntimeCallbacks(onPreRuns);
      }
      function initRuntime() {
        runtimeInitialized = true;
        if (!Module["noFSInit"] && !FS.initialized) FS.init();
        wasmExports["__wasm_call_ctors"]();
        FS.ignorePermissions = false;
      }
      function postRun() {
        if (Module["postRun"]) {
          if (typeof Module["postRun"] == "function") Module["postRun"] = [Module["postRun"]];
          while (Module["postRun"].length) addOnPostRun(Module["postRun"].shift());
        }
        callRuntimeCallbacks(onPostRuns);
      }
      function abort(what) {
        Module["onAbort"]?.(what);
        what = "Aborted(" + what + ")";
        err(what);
        ABORT = true;
        what += ". Build with -sASSERTIONS for more info.";
        var e = new WebAssembly.RuntimeError(what);
        readyPromiseReject?.(e);
        throw e;
      }
      var wasmBinaryFile;
      function findWasmBinary() {
        if (Module["locateFile"]) return locateFile("sqlite3.wasm");
        return new URL("sqlite3.wasm", (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('dls-analysis.umd.js', document.baseURI).href))).href;
      }
      function getBinarySync(file) {
        if (file == wasmBinaryFile && wasmBinary) return new Uint8Array(wasmBinary);
        if (readBinary) return readBinary(file);
        throw "both async and sync fetching of the wasm failed";
      }
      async function getWasmBinary(binaryFile) {
        if (!wasmBinary) try {
          var response = await readAsync(binaryFile);
          return new Uint8Array(response);
        } catch {}
        return getBinarySync(binaryFile);
      }
      async function instantiateArrayBuffer(binaryFile, imports) {
        try {
          var binary = await getWasmBinary(binaryFile);
          return await WebAssembly.instantiate(binary, imports);
        } catch (reason) {
          err(`failed to asynchronously prepare wasm: ${reason}`);
          abort(reason);
        }
      }
      async function instantiateAsync(binary, binaryFile, imports) {
        if (!binary) try {
          var response = fetch(binaryFile, {
            credentials: "same-origin"
          });
          return await WebAssembly.instantiateStreaming(response, imports);
        } catch (reason) {
          err(`wasm streaming compile failed: ${reason}`);
          err("falling back to ArrayBuffer instantiation");
        }
        return instantiateArrayBuffer(binaryFile, imports);
      }
      function getWasmImports() {
        return {
          "env": wasmImports,
          "wasi_snapshot_preview1": wasmImports
        };
      }
      async function createWasm() {
        function receiveInstance(instance, module) {
          wasmExports = instance.exports;
          assignWasmExports(wasmExports);
          return wasmExports;
        }
        function receiveInstantiationResult(result) {
          return receiveInstance(result["instance"]);
        }
        var info = getWasmImports();
        if (Module["instantiateWasm"]) return new Promise((resolve, reject) => {
          Module["instantiateWasm"](info, (inst, mod) => {
            resolve(receiveInstance(inst));
          });
        });
        wasmBinaryFile ??= findWasmBinary();
        return receiveInstantiationResult(await instantiateAsync(wasmBinary, wasmBinaryFile, info));
      }
      var callRuntimeCallbacks = callbacks => {
        while (callbacks.length > 0) callbacks.shift()(Module);
      };
      var onPostRuns = [];
      var addOnPostRun = cb => onPostRuns.push(cb);
      var onPreRuns = [];
      var addOnPreRun = cb => onPreRuns.push(cb);
      var wasmMemory;
      var PATH = {
        isAbs: path => path.charAt(0) === "/",
        splitPath: filename => {
          return /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(filename).slice(1);
        },
        normalizeArray: (parts, allowAboveRoot) => {
          var up = 0;
          for (var i = parts.length - 1; i >= 0; i--) {
            var last = parts[i];
            if (last === ".") parts.splice(i, 1);else if (last === "..") {
              parts.splice(i, 1);
              up++;
            } else if (up) {
              parts.splice(i, 1);
              up--;
            }
          }
          if (allowAboveRoot) for (; up; up--) parts.unshift("..");
          return parts;
        },
        normalize: path => {
          var isAbsolute = PATH.isAbs(path),
            trailingSlash = path.slice(-1) === "/";
          path = PATH.normalizeArray(path.split("/").filter(p => !!p), !isAbsolute).join("/");
          if (!path && !isAbsolute) path = ".";
          if (path && trailingSlash) path += "/";
          return (isAbsolute ? "/" : "") + path;
        },
        dirname: path => {
          var result = PATH.splitPath(path),
            root = result[0],
            dir = result[1];
          if (!root && !dir) return ".";
          if (dir) dir = dir.slice(0, -1);
          return root + dir;
        },
        basename: path => path && path.match(/([^\/]+|\/)\/*$/)[1],
        join: (...paths) => PATH.normalize(paths.join("/")),
        join2: (l, r) => PATH.normalize(l + "/" + r)
      };
      var initRandomFill = () => {
        return view => crypto.getRandomValues(view);
      };
      var randomFill = view => {
        (randomFill = initRandomFill())(view);
      };
      var PATH_FS = {
        resolve: (...args) => {
          var resolvedPath = "",
            resolvedAbsolute = false;
          for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
            var path = i >= 0 ? args[i] : FS.cwd();
            if (typeof path != "string") throw new TypeError("Arguments to path.resolve must be strings");else if (!path) return "";
            resolvedPath = path + "/" + resolvedPath;
            resolvedAbsolute = PATH.isAbs(path);
          }
          resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter(p => !!p), !resolvedAbsolute).join("/");
          return (resolvedAbsolute ? "/" : "") + resolvedPath || ".";
        },
        relative: (from, to) => {
          from = PATH_FS.resolve(from).slice(1);
          to = PATH_FS.resolve(to).slice(1);
          function trim(arr) {
            var start = 0;
            for (; start < arr.length; start++) if (arr[start] !== "") break;
            var end = arr.length - 1;
            for (; end >= 0; end--) if (arr[end] !== "") break;
            if (start > end) return [];
            return arr.slice(start, end - start + 1);
          }
          var fromParts = trim(from.split("/"));
          var toParts = trim(to.split("/"));
          var length = Math.min(fromParts.length, toParts.length);
          var samePartsLength = length;
          for (var i = 0; i < length; i++) if (fromParts[i] !== toParts[i]) {
            samePartsLength = i;
            break;
          }
          var outputParts = [];
          for (var i = samePartsLength; i < fromParts.length; i++) outputParts.push("..");
          outputParts = outputParts.concat(toParts.slice(samePartsLength));
          return outputParts.join("/");
        }
      };
      var UTF8Decoder = new TextDecoder();
      var findStringEnd = (heapOrArray, idx, maxBytesToRead, ignoreNul) => {
        var maxIdx = idx + maxBytesToRead;
        while (heapOrArray[idx] && !(idx >= maxIdx)) ++idx;
        return idx;
      };
      var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead, ignoreNul) => {
        var endPtr = findStringEnd(heapOrArray, idx, maxBytesToRead);
        return UTF8Decoder.decode(heapOrArray.buffer ? heapOrArray.subarray(idx, endPtr) : new Uint8Array(heapOrArray.slice(idx, endPtr)));
      };
      var FS_stdin_getChar_buffer = [];
      var lengthBytesUTF8 = str => {
        var len = 0;
        for (var i = 0; i < str.length; ++i) {
          var c = str.charCodeAt(i);
          if (c <= 127) len++;else if (c <= 2047) len += 2;else if (c >= 55296 && c <= 57343) {
            len += 4;
            ++i;
          } else len += 3;
        }
        return len;
      };
      var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => {
        if (!(maxBytesToWrite > 0)) return 0;
        var startIdx = outIdx;
        var endIdx = outIdx + maxBytesToWrite - 1;
        for (var i = 0; i < str.length; ++i) {
          var u = str.codePointAt(i);
          if (u <= 127) {
            if (outIdx >= endIdx) break;
            heap[outIdx++] = u;
          } else if (u <= 2047) {
            if (outIdx + 1 >= endIdx) break;
            heap[outIdx++] = 192 | u >> 6;
            heap[outIdx++] = 128 | u & 63;
          } else if (u <= 65535) {
            if (outIdx + 2 >= endIdx) break;
            heap[outIdx++] = 224 | u >> 12;
            heap[outIdx++] = 128 | u >> 6 & 63;
            heap[outIdx++] = 128 | u & 63;
          } else {
            if (outIdx + 3 >= endIdx) break;
            heap[outIdx++] = 240 | u >> 18;
            heap[outIdx++] = 128 | u >> 12 & 63;
            heap[outIdx++] = 128 | u >> 6 & 63;
            heap[outIdx++] = 128 | u & 63;
            i++;
          }
        }
        heap[outIdx] = 0;
        return outIdx - startIdx;
      };
      var intArrayFromString = (stringy, dontAddNull, length) => {
        var len = lengthBytesUTF8(stringy) + 1;
        var u8array = new Array(len);
        var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);
        u8array.length = numBytesWritten;
        return u8array;
      };
      var FS_stdin_getChar = () => {
        if (!FS_stdin_getChar_buffer.length) {
          var result = null;
          if (globalThis.window?.prompt) {
            result = window.prompt("Input: ");
            if (result !== null) result += "\n";
          }
          if (!result) return null;
          FS_stdin_getChar_buffer = intArrayFromString(result);
        }
        return FS_stdin_getChar_buffer.shift();
      };
      var TTY = {
        ttys: [],
        init() {},
        shutdown() {},
        register(dev, ops) {
          TTY.ttys[dev] = {
            input: [],
            output: [],
            ops
          };
          FS.registerDevice(dev, TTY.stream_ops);
        },
        stream_ops: {
          open(stream) {
            var tty = TTY.ttys[stream.node.rdev];
            if (!tty) throw new FS.ErrnoError(43);
            stream.tty = tty;
            stream.seekable = false;
          },
          close(stream) {
            stream.tty.ops.fsync(stream.tty);
          },
          fsync(stream) {
            stream.tty.ops.fsync(stream.tty);
          },
          read(stream, buffer, offset, length, pos) {
            if (!stream.tty || !stream.tty.ops.get_char) throw new FS.ErrnoError(60);
            var bytesRead = 0;
            for (var i = 0; i < length; i++) {
              var result;
              try {
                result = stream.tty.ops.get_char(stream.tty);
              } catch (e) {
                throw new FS.ErrnoError(29);
              }
              if (result === void 0 && bytesRead === 0) throw new FS.ErrnoError(6);
              if (result === null || result === void 0) break;
              bytesRead++;
              buffer[offset + i] = result;
            }
            if (bytesRead) stream.node.atime = Date.now();
            return bytesRead;
          },
          write(stream, buffer, offset, length, pos) {
            if (!stream.tty || !stream.tty.ops.put_char) throw new FS.ErrnoError(60);
            try {
              for (var i = 0; i < length; i++) stream.tty.ops.put_char(stream.tty, buffer[offset + i]);
            } catch (e) {
              throw new FS.ErrnoError(29);
            }
            if (length) stream.node.mtime = stream.node.ctime = Date.now();
            return i;
          }
        },
        default_tty_ops: {
          get_char(tty) {
            return FS_stdin_getChar();
          },
          put_char(tty, val) {
            if (val === null || val === 10) {
              out(UTF8ArrayToString(tty.output));
              tty.output = [];
            } else if (val != 0) tty.output.push(val);
          },
          fsync(tty) {
            if (tty.output?.length > 0) {
              out(UTF8ArrayToString(tty.output));
              tty.output = [];
            }
          },
          ioctl_tcgets(tty) {
            return {
              c_iflag: 25856,
              c_oflag: 5,
              c_cflag: 191,
              c_lflag: 35387,
              c_cc: [3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 0, 18, 15, 23, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
            };
          },
          ioctl_tcsets(tty, optional_actions, data) {
            return 0;
          },
          ioctl_tiocgwinsz(tty) {
            return [24, 80];
          }
        },
        default_tty1_ops: {
          put_char(tty, val) {
            if (val === null || val === 10) {
              err(UTF8ArrayToString(tty.output));
              tty.output = [];
            } else if (val != 0) tty.output.push(val);
          },
          fsync(tty) {
            if (tty.output?.length > 0) {
              err(UTF8ArrayToString(tty.output));
              tty.output = [];
            }
          }
        }
      };
      var zeroMemory = (ptr, size) => HEAPU8.fill(0, ptr, ptr + size);
      var alignMemory = (size, alignment) => {
        return Math.ceil(size / alignment) * alignment;
      };
      var mmapAlloc = size => {
        size = alignMemory(size, 65536);
        var ptr = _emscripten_builtin_memalign(65536, size);
        if (ptr) zeroMemory(ptr, size);
        return ptr;
      };
      var MEMFS = {
        ops_table: null,
        mount(mount) {
          return MEMFS.createNode(null, "/", 16895, 0);
        },
        createNode(parent, name, mode, dev) {
          if (FS.isBlkdev(mode) || FS.isFIFO(mode)) throw new FS.ErrnoError(63);
          MEMFS.ops_table ||= {
            dir: {
              node: {
                getattr: MEMFS.node_ops.getattr,
                setattr: MEMFS.node_ops.setattr,
                lookup: MEMFS.node_ops.lookup,
                mknod: MEMFS.node_ops.mknod,
                rename: MEMFS.node_ops.rename,
                unlink: MEMFS.node_ops.unlink,
                rmdir: MEMFS.node_ops.rmdir,
                readdir: MEMFS.node_ops.readdir,
                symlink: MEMFS.node_ops.symlink
              },
              stream: {
                llseek: MEMFS.stream_ops.llseek
              }
            },
            file: {
              node: {
                getattr: MEMFS.node_ops.getattr,
                setattr: MEMFS.node_ops.setattr
              },
              stream: {
                llseek: MEMFS.stream_ops.llseek,
                read: MEMFS.stream_ops.read,
                write: MEMFS.stream_ops.write,
                mmap: MEMFS.stream_ops.mmap,
                msync: MEMFS.stream_ops.msync
              }
            },
            link: {
              node: {
                getattr: MEMFS.node_ops.getattr,
                setattr: MEMFS.node_ops.setattr,
                readlink: MEMFS.node_ops.readlink
              },
              stream: {}
            },
            chrdev: {
              node: {
                getattr: MEMFS.node_ops.getattr,
                setattr: MEMFS.node_ops.setattr
              },
              stream: FS.chrdev_stream_ops
            }
          };
          var node = FS.createNode(parent, name, mode, dev);
          if (FS.isDir(node.mode)) {
            node.node_ops = MEMFS.ops_table.dir.node;
            node.stream_ops = MEMFS.ops_table.dir.stream;
            node.contents = {};
          } else if (FS.isFile(node.mode)) {
            node.node_ops = MEMFS.ops_table.file.node;
            node.stream_ops = MEMFS.ops_table.file.stream;
            node.usedBytes = 0;
            node.contents = null;
          } else if (FS.isLink(node.mode)) {
            node.node_ops = MEMFS.ops_table.link.node;
            node.stream_ops = MEMFS.ops_table.link.stream;
          } else if (FS.isChrdev(node.mode)) {
            node.node_ops = MEMFS.ops_table.chrdev.node;
            node.stream_ops = MEMFS.ops_table.chrdev.stream;
          }
          node.atime = node.mtime = node.ctime = Date.now();
          if (parent) {
            parent.contents[name] = node;
            parent.atime = parent.mtime = parent.ctime = node.atime;
          }
          return node;
        },
        getFileDataAsTypedArray(node) {
          if (!node.contents) return new Uint8Array(0);
          if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes);
          return new Uint8Array(node.contents);
        },
        expandFileStorage(node, newCapacity) {
          var prevCapacity = node.contents ? node.contents.length : 0;
          if (prevCapacity >= newCapacity) return;
          newCapacity = Math.max(newCapacity, prevCapacity * (prevCapacity < 1024 * 1024 ? 2 : 1.125) >>> 0);
          if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256);
          var oldContents = node.contents;
          node.contents = new Uint8Array(newCapacity);
          if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0);
        },
        resizeFileStorage(node, newSize) {
          if (node.usedBytes == newSize) return;
          if (newSize == 0) {
            node.contents = null;
            node.usedBytes = 0;
          } else {
            var oldContents = node.contents;
            node.contents = new Uint8Array(newSize);
            if (oldContents) node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes)));
            node.usedBytes = newSize;
          }
        },
        node_ops: {
          getattr(node) {
            var attr = {};
            attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
            attr.ino = node.id;
            attr.mode = node.mode;
            attr.nlink = 1;
            attr.uid = 0;
            attr.gid = 0;
            attr.rdev = node.rdev;
            if (FS.isDir(node.mode)) attr.size = 4096;else if (FS.isFile(node.mode)) attr.size = node.usedBytes;else if (FS.isLink(node.mode)) attr.size = node.link.length;else attr.size = 0;
            attr.atime = new Date(node.atime);
            attr.mtime = new Date(node.mtime);
            attr.ctime = new Date(node.ctime);
            attr.blksize = 4096;
            attr.blocks = Math.ceil(attr.size / attr.blksize);
            return attr;
          },
          setattr(node, attr) {
            for (const key of ["mode", "atime", "mtime", "ctime"]) if (attr[key] != null) node[key] = attr[key];
            if (attr.size !== void 0) MEMFS.resizeFileStorage(node, attr.size);
          },
          lookup(parent, name) {
            if (!MEMFS.doesNotExistError) {
              MEMFS.doesNotExistError = new FS.ErrnoError(44);
              MEMFS.doesNotExistError.stack = "<generic error, no stack>";
            }
            throw MEMFS.doesNotExistError;
          },
          mknod(parent, name, mode, dev) {
            return MEMFS.createNode(parent, name, mode, dev);
          },
          rename(old_node, new_dir, new_name) {
            var new_node;
            try {
              new_node = FS.lookupNode(new_dir, new_name);
            } catch (e) {}
            if (new_node) {
              if (FS.isDir(old_node.mode)) for (var i in new_node.contents) throw new FS.ErrnoError(55);
              FS.hashRemoveNode(new_node);
            }
            delete old_node.parent.contents[old_node.name];
            new_dir.contents[new_name] = old_node;
            old_node.name = new_name;
            new_dir.ctime = new_dir.mtime = old_node.parent.ctime = old_node.parent.mtime = Date.now();
          },
          unlink(parent, name) {
            delete parent.contents[name];
            parent.ctime = parent.mtime = Date.now();
          },
          rmdir(parent, name) {
            for (var i in FS.lookupNode(parent, name).contents) throw new FS.ErrnoError(55);
            delete parent.contents[name];
            parent.ctime = parent.mtime = Date.now();
          },
          readdir(node) {
            return [".", "..", ...Object.keys(node.contents)];
          },
          symlink(parent, newname, oldpath) {
            var node = MEMFS.createNode(parent, newname, 41471, 0);
            node.link = oldpath;
            return node;
          },
          readlink(node) {
            if (!FS.isLink(node.mode)) throw new FS.ErrnoError(28);
            return node.link;
          }
        },
        stream_ops: {
          read(stream, buffer, offset, length, position) {
            var contents = stream.node.contents;
            if (position >= stream.node.usedBytes) return 0;
            var size = Math.min(stream.node.usedBytes - position, length);
            if (size > 8 && contents.subarray) buffer.set(contents.subarray(position, position + size), offset);else for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];
            return size;
          },
          write(stream, buffer, offset, length, position, canOwn) {
            if (buffer.buffer === HEAP8.buffer) canOwn = false;
            if (!length) return 0;
            var node = stream.node;
            node.mtime = node.ctime = Date.now();
            if (buffer.subarray && (!node.contents || node.contents.subarray)) {
              if (canOwn) {
                node.contents = buffer.subarray(offset, offset + length);
                node.usedBytes = length;
                return length;
              } else if (node.usedBytes === 0 && position === 0) {
                node.contents = buffer.slice(offset, offset + length);
                node.usedBytes = length;
                return length;
              } else if (position + length <= node.usedBytes) {
                node.contents.set(buffer.subarray(offset, offset + length), position);
                return length;
              }
            }
            MEMFS.expandFileStorage(node, position + length);
            if (node.contents.subarray && buffer.subarray) node.contents.set(buffer.subarray(offset, offset + length), position);else for (var i = 0; i < length; i++) node.contents[position + i] = buffer[offset + i];
            node.usedBytes = Math.max(node.usedBytes, position + length);
            return length;
          },
          llseek(stream, offset, whence) {
            var position = offset;
            if (whence === 1) position += stream.position;else if (whence === 2) {
              if (FS.isFile(stream.node.mode)) position += stream.node.usedBytes;
            }
            if (position < 0) throw new FS.ErrnoError(28);
            return position;
          },
          mmap(stream, length, position, prot, flags) {
            if (!FS.isFile(stream.node.mode)) throw new FS.ErrnoError(43);
            var ptr;
            var allocated;
            var contents = stream.node.contents;
            if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) {
              allocated = false;
              ptr = contents.byteOffset;
            } else {
              allocated = true;
              ptr = mmapAlloc(length);
              if (!ptr) throw new FS.ErrnoError(48);
              if (contents) {
                if (position > 0 || position + length < contents.length) if (contents.subarray) contents = contents.subarray(position, position + length);else contents = Array.prototype.slice.call(contents, position, position + length);
                HEAP8.set(contents, ptr);
              }
            }
            return {
              ptr,
              allocated
            };
          },
          msync(stream, buffer, offset, length, mmapFlags) {
            MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);
            return 0;
          }
        }
      };
      var FS_modeStringToFlags = str => {
        var flags = {
          "r": 0,
          "r+": 2,
          "w": 577,
          "w+": 578,
          "a": 1089,
          "a+": 1090
        }[str];
        if (typeof flags == "undefined") throw new Error(`Unknown file open mode: ${str}`);
        return flags;
      };
      var FS_getMode = (canRead, canWrite) => {
        var mode = 0;
        if (canRead) mode |= 365;
        if (canWrite) mode |= 146;
        return mode;
      };
      var asyncLoad = async url => {
        var arrayBuffer = await readAsync(url);
        return new Uint8Array(arrayBuffer);
      };
      var FS_createDataFile = (...args) => FS.createDataFile(...args);
      var runDependencies = 0;
      var dependenciesFulfilled = null;
      var removeRunDependency = id => {
        runDependencies--;
        Module["monitorRunDependencies"]?.(runDependencies);
        if (runDependencies == 0) {
          if (dependenciesFulfilled) {
            var callback = dependenciesFulfilled;
            dependenciesFulfilled = null;
            callback();
          }
        }
      };
      var addRunDependency = id => {
        runDependencies++;
        Module["monitorRunDependencies"]?.(runDependencies);
      };
      var preloadPlugins = [];
      var FS_handledByPreloadPlugin = async (byteArray, fullname) => {
        if (typeof Browser != "undefined") Browser.init();
        for (var plugin of preloadPlugins) if (plugin["canHandle"](fullname)) return plugin["handle"](byteArray, fullname);
        return byteArray;
      };
      var FS_preloadFile = async (parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish) => {
        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent;
        addRunDependency();
        try {
          var byteArray = url;
          if (typeof url == "string") byteArray = await asyncLoad(url);
          byteArray = await FS_handledByPreloadPlugin(byteArray, fullname);
          preFinish?.();
          if (!dontCreateFile) FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
        } finally {
          removeRunDependency();
        }
      };
      var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => {
        FS_preloadFile(parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish).then(onload).catch(onerror);
      };
      var FS = {
        root: null,
        mounts: [],
        devices: {},
        streams: [],
        nextInode: 1,
        nameTable: null,
        currentPath: "/",
        initialized: false,
        ignorePermissions: true,
        filesystems: null,
        syncFSRequests: 0,
        readFiles: {},
        ErrnoError: class {
          name = "ErrnoError";
          constructor(errno) {
            this.errno = errno;
          }
        },
        FSStream: class {
          shared = {};
          get object() {
            return this.node;
          }
          set object(val) {
            this.node = val;
          }
          get isRead() {
            return (this.flags & 2097155) !== 1;
          }
          get isWrite() {
            return (this.flags & 2097155) !== 0;
          }
          get isAppend() {
            return this.flags & 1024;
          }
          get flags() {
            return this.shared.flags;
          }
          set flags(val) {
            this.shared.flags = val;
          }
          get position() {
            return this.shared.position;
          }
          set position(val) {
            this.shared.position = val;
          }
        },
        FSNode: class {
          node_ops = {};
          stream_ops = {};
          readMode = 365;
          writeMode = 146;
          mounted = null;
          constructor(parent, name, mode, rdev) {
            if (!parent) parent = this;
            this.parent = parent;
            this.mount = parent.mount;
            this.id = FS.nextInode++;
            this.name = name;
            this.mode = mode;
            this.rdev = rdev;
            this.atime = this.mtime = this.ctime = Date.now();
          }
          get read() {
            return (this.mode & this.readMode) === this.readMode;
          }
          set read(val) {
            val ? this.mode |= this.readMode : this.mode &= ~this.readMode;
          }
          get write() {
            return (this.mode & this.writeMode) === this.writeMode;
          }
          set write(val) {
            val ? this.mode |= this.writeMode : this.mode &= ~this.writeMode;
          }
          get isFolder() {
            return FS.isDir(this.mode);
          }
          get isDevice() {
            return FS.isChrdev(this.mode);
          }
        },
        lookupPath(path, opts = {}) {
          if (!path) throw new FS.ErrnoError(44);
          opts.follow_mount ??= true;
          if (!PATH.isAbs(path)) path = FS.cwd() + "/" + path;
          linkloop: for (var nlinks = 0; nlinks < 40; nlinks++) {
            var parts = path.split("/").filter(p => !!p);
            var current = FS.root;
            var current_path = "/";
            for (var i = 0; i < parts.length; i++) {
              var islast = i === parts.length - 1;
              if (islast && opts.parent) break;
              if (parts[i] === ".") continue;
              if (parts[i] === "..") {
                current_path = PATH.dirname(current_path);
                if (FS.isRoot(current)) {
                  path = current_path + "/" + parts.slice(i + 1).join("/");
                  nlinks--;
                  continue linkloop;
                } else current = current.parent;
                continue;
              }
              current_path = PATH.join2(current_path, parts[i]);
              try {
                current = FS.lookupNode(current, parts[i]);
              } catch (e) {
                if (e?.errno === 44 && islast && opts.noent_okay) return {
                  path: current_path
                };
                throw e;
              }
              if (FS.isMountpoint(current) && (!islast || opts.follow_mount)) current = current.mounted.root;
              if (FS.isLink(current.mode) && (!islast || opts.follow)) {
                if (!current.node_ops.readlink) throw new FS.ErrnoError(52);
                var link = current.node_ops.readlink(current);
                if (!PATH.isAbs(link)) link = PATH.dirname(current_path) + "/" + link;
                path = link + "/" + parts.slice(i + 1).join("/");
                continue linkloop;
              }
            }
            return {
              path: current_path,
              node: current
            };
          }
          throw new FS.ErrnoError(32);
        },
        getPath(node) {
          var path;
          while (true) {
            if (FS.isRoot(node)) {
              var mount = node.mount.mountpoint;
              if (!path) return mount;
              return mount[mount.length - 1] !== "/" ? `${mount}/${path}` : mount + path;
            }
            path = path ? `${node.name}/${path}` : node.name;
            node = node.parent;
          }
        },
        hashName(parentid, name) {
          var hash = 0;
          for (var i = 0; i < name.length; i++) hash = (hash << 5) - hash + name.charCodeAt(i) | 0;
          return (parentid + hash >>> 0) % FS.nameTable.length;
        },
        hashAddNode(node) {
          var hash = FS.hashName(node.parent.id, node.name);
          node.name_next = FS.nameTable[hash];
          FS.nameTable[hash] = node;
        },
        hashRemoveNode(node) {
          var hash = FS.hashName(node.parent.id, node.name);
          if (FS.nameTable[hash] === node) FS.nameTable[hash] = node.name_next;else {
            var current = FS.nameTable[hash];
            while (current) {
              if (current.name_next === node) {
                current.name_next = node.name_next;
                break;
              }
              current = current.name_next;
            }
          }
        },
        lookupNode(parent, name) {
          var errCode = FS.mayLookup(parent);
          if (errCode) throw new FS.ErrnoError(errCode);
          var hash = FS.hashName(parent.id, name);
          for (var node = FS.nameTable[hash]; node; node = node.name_next) {
            var nodeName = node.name;
            if (node.parent.id === parent.id && nodeName === name) return node;
          }
          return FS.lookup(parent, name);
        },
        createNode(parent, name, mode, rdev) {
          var node = new FS.FSNode(parent, name, mode, rdev);
          FS.hashAddNode(node);
          return node;
        },
        destroyNode(node) {
          FS.hashRemoveNode(node);
        },
        isRoot(node) {
          return node === node.parent;
        },
        isMountpoint(node) {
          return !!node.mounted;
        },
        isFile(mode) {
          return (mode & 61440) === 32768;
        },
        isDir(mode) {
          return (mode & 61440) === 16384;
        },
        isLink(mode) {
          return (mode & 61440) === 40960;
        },
        isChrdev(mode) {
          return (mode & 61440) === 8192;
        },
        isBlkdev(mode) {
          return (mode & 61440) === 24576;
        },
        isFIFO(mode) {
          return (mode & 61440) === 4096;
        },
        isSocket(mode) {
          return (mode & 49152) === 49152;
        },
        flagsToPermissionString(flag) {
          var perms = ["r", "w", "rw"][flag & 3];
          if (flag & 512) perms += "w";
          return perms;
        },
        nodePermissions(node, perms) {
          if (FS.ignorePermissions) return 0;
          if (perms.includes("r") && !(node.mode & 292)) return 2;else if (perms.includes("w") && !(node.mode & 146)) return 2;else if (perms.includes("x") && !(node.mode & 73)) return 2;
          return 0;
        },
        mayLookup(dir) {
          if (!FS.isDir(dir.mode)) return 54;
          var errCode = FS.nodePermissions(dir, "x");
          if (errCode) return errCode;
          if (!dir.node_ops.lookup) return 2;
          return 0;
        },
        mayCreate(dir, name) {
          if (!FS.isDir(dir.mode)) return 54;
          try {
            FS.lookupNode(dir, name);
            return 20;
          } catch (e) {}
          return FS.nodePermissions(dir, "wx");
        },
        mayDelete(dir, name, isdir) {
          var node;
          try {
            node = FS.lookupNode(dir, name);
          } catch (e) {
            return e.errno;
          }
          var errCode = FS.nodePermissions(dir, "wx");
          if (errCode) return errCode;
          if (isdir) {
            if (!FS.isDir(node.mode)) return 54;
            if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) return 10;
          } else if (FS.isDir(node.mode)) return 31;
          return 0;
        },
        mayOpen(node, flags) {
          if (!node) return 44;
          if (FS.isLink(node.mode)) return 32;else if (FS.isDir(node.mode)) {
            if (FS.flagsToPermissionString(flags) !== "r" || flags & 576) return 31;
          }
          return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
        },
        checkOpExists(op, err) {
          if (!op) throw new FS.ErrnoError(err);
          return op;
        },
        MAX_OPEN_FDS: 4096,
        nextfd() {
          for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) if (!FS.streams[fd]) return fd;
          throw new FS.ErrnoError(33);
        },
        getStreamChecked(fd) {
          var stream = FS.getStream(fd);
          if (!stream) throw new FS.ErrnoError(8);
          return stream;
        },
        getStream: fd => FS.streams[fd],
        createStream(stream, fd = -1) {
          stream = Object.assign(new FS.FSStream(), stream);
          if (fd == -1) fd = FS.nextfd();
          stream.fd = fd;
          FS.streams[fd] = stream;
          return stream;
        },
        closeStream(fd) {
          FS.streams[fd] = null;
        },
        dupStream(origStream, fd = -1) {
          var stream = FS.createStream(origStream, fd);
          stream.stream_ops?.dup?.(stream);
          return stream;
        },
        doSetAttr(stream, node, attr) {
          var setattr = stream?.stream_ops.setattr;
          var arg = setattr ? stream : node;
          setattr ??= node.node_ops.setattr;
          FS.checkOpExists(setattr, 63);
          setattr(arg, attr);
        },
        chrdev_stream_ops: {
          open(stream) {
            stream.stream_ops = FS.getDevice(stream.node.rdev).stream_ops;
            stream.stream_ops.open?.(stream);
          },
          llseek() {
            throw new FS.ErrnoError(70);
          }
        },
        major: dev => dev >> 8,
        minor: dev => dev & 255,
        makedev: (ma, mi) => ma << 8 | mi,
        registerDevice(dev, ops) {
          FS.devices[dev] = {
            stream_ops: ops
          };
        },
        getDevice: dev => FS.devices[dev],
        getMounts(mount) {
          var mounts = [];
          var check = [mount];
          while (check.length) {
            var m = check.pop();
            mounts.push(m);
            check.push(...m.mounts);
          }
          return mounts;
        },
        syncfs(populate, callback) {
          if (typeof populate == "function") {
            callback = populate;
            populate = false;
          }
          FS.syncFSRequests++;
          if (FS.syncFSRequests > 1) err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`);
          var mounts = FS.getMounts(FS.root.mount);
          var completed = 0;
          function doCallback(errCode) {
            FS.syncFSRequests--;
            return callback(errCode);
          }
          function done(errCode) {
            if (errCode) {
              if (!done.errored) {
                done.errored = true;
                return doCallback(errCode);
              }
              return;
            }
            if (++completed >= mounts.length) doCallback(null);
          }
          for (var mount of mounts) if (mount.type.syncfs) mount.type.syncfs(mount, populate, done);else done(null);
        },
        mount(type, opts, mountpoint) {
          var root = mountpoint === "/";
          var pseudo = !mountpoint;
          var node;
          if (root && FS.root) throw new FS.ErrnoError(10);else if (!root && !pseudo) {
            var lookup = FS.lookupPath(mountpoint, {
              follow_mount: false
            });
            mountpoint = lookup.path;
            node = lookup.node;
            if (FS.isMountpoint(node)) throw new FS.ErrnoError(10);
            if (!FS.isDir(node.mode)) throw new FS.ErrnoError(54);
          }
          var mount = {
            type,
            opts,
            mountpoint,
            mounts: []
          };
          var mountRoot = type.mount(mount);
          mountRoot.mount = mount;
          mount.root = mountRoot;
          if (root) FS.root = mountRoot;else if (node) {
            node.mounted = mount;
            if (node.mount) node.mount.mounts.push(mount);
          }
          return mountRoot;
        },
        unmount(mountpoint) {
          var lookup = FS.lookupPath(mountpoint, {
            follow_mount: false
          });
          if (!FS.isMountpoint(lookup.node)) throw new FS.ErrnoError(28);
          var node = lookup.node;
          var mount = node.mounted;
          var mounts = FS.getMounts(mount);
          for (var [hash, current] of Object.entries(FS.nameTable)) while (current) {
            var next = current.name_next;
            if (mounts.includes(current.mount)) FS.destroyNode(current);
            current = next;
          }
          node.mounted = null;
          var idx = node.mount.mounts.indexOf(mount);
          node.mount.mounts.splice(idx, 1);
        },
        lookup(parent, name) {
          return parent.node_ops.lookup(parent, name);
        },
        mknod(path, mode, dev) {
          var parent = FS.lookupPath(path, {
            parent: true
          }).node;
          var name = PATH.basename(path);
          if (!name) throw new FS.ErrnoError(28);
          if (name === "." || name === "..") throw new FS.ErrnoError(20);
          var errCode = FS.mayCreate(parent, name);
          if (errCode) throw new FS.ErrnoError(errCode);
          if (!parent.node_ops.mknod) throw new FS.ErrnoError(63);
          return parent.node_ops.mknod(parent, name, mode, dev);
        },
        statfs(path) {
          return FS.statfsNode(FS.lookupPath(path, {
            follow: true
          }).node);
        },
        statfsStream(stream) {
          return FS.statfsNode(stream.node);
        },
        statfsNode(node) {
          var rtn = {
            bsize: 4096,
            frsize: 4096,
            blocks: 1e6,
            bfree: 5e5,
            bavail: 5e5,
            files: FS.nextInode,
            ffree: FS.nextInode - 1,
            fsid: 42,
            flags: 2,
            namelen: 255
          };
          if (node.node_ops.statfs) Object.assign(rtn, node.node_ops.statfs(node.mount.opts.root));
          return rtn;
        },
        create(path, mode = 438) {
          mode &= 4095;
          mode |= 32768;
          return FS.mknod(path, mode, 0);
        },
        mkdir(path, mode = 511) {
          mode &= 1023;
          mode |= 16384;
          return FS.mknod(path, mode, 0);
        },
        mkdirTree(path, mode) {
          var dirs = path.split("/");
          var d = "";
          for (var dir of dirs) {
            if (!dir) continue;
            if (d || PATH.isAbs(path)) d += "/";
            d += dir;
            try {
              FS.mkdir(d, mode);
            } catch (e) {
              if (e.errno != 20) throw e;
            }
          }
        },
        mkdev(path, mode, dev) {
          if (typeof dev == "undefined") {
            dev = mode;
            mode = 438;
          }
          mode |= 8192;
          return FS.mknod(path, mode, dev);
        },
        symlink(oldpath, newpath) {
          if (!PATH_FS.resolve(oldpath)) throw new FS.ErrnoError(44);
          var parent = FS.lookupPath(newpath, {
            parent: true
          }).node;
          if (!parent) throw new FS.ErrnoError(44);
          var newname = PATH.basename(newpath);
          var errCode = FS.mayCreate(parent, newname);
          if (errCode) throw new FS.ErrnoError(errCode);
          if (!parent.node_ops.symlink) throw new FS.ErrnoError(63);
          return parent.node_ops.symlink(parent, newname, oldpath);
        },
        rename(old_path, new_path) {
          var old_dirname = PATH.dirname(old_path);
          var new_dirname = PATH.dirname(new_path);
          var old_name = PATH.basename(old_path);
          var new_name = PATH.basename(new_path);
          var lookup = FS.lookupPath(old_path, {
              parent: true
            }),
            old_dir = lookup.node,
            new_dir;
          lookup = FS.lookupPath(new_path, {
            parent: true
          });
          new_dir = lookup.node;
          if (!old_dir || !new_dir) throw new FS.ErrnoError(44);
          if (old_dir.mount !== new_dir.mount) throw new FS.ErrnoError(75);
          var old_node = FS.lookupNode(old_dir, old_name);
          var relative = PATH_FS.relative(old_path, new_dirname);
          if (relative.charAt(0) !== ".") throw new FS.ErrnoError(28);
          relative = PATH_FS.relative(new_path, old_dirname);
          if (relative.charAt(0) !== ".") throw new FS.ErrnoError(55);
          var new_node;
          try {
            new_node = FS.lookupNode(new_dir, new_name);
          } catch (e) {}
          if (old_node === new_node) return;
          var isdir = FS.isDir(old_node.mode);
          var errCode = FS.mayDelete(old_dir, old_name, isdir);
          if (errCode) throw new FS.ErrnoError(errCode);
          errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name);
          if (errCode) throw new FS.ErrnoError(errCode);
          if (!old_dir.node_ops.rename) throw new FS.ErrnoError(63);
          if (FS.isMountpoint(old_node) || new_node && FS.isMountpoint(new_node)) throw new FS.ErrnoError(10);
          if (new_dir !== old_dir) {
            errCode = FS.nodePermissions(old_dir, "w");
            if (errCode) throw new FS.ErrnoError(errCode);
          }
          FS.hashRemoveNode(old_node);
          try {
            old_dir.node_ops.rename(old_node, new_dir, new_name);
            old_node.parent = new_dir;
          } catch (e) {
            throw e;
          } finally {
            FS.hashAddNode(old_node);
          }
        },
        rmdir(path) {
          var parent = FS.lookupPath(path, {
            parent: true
          }).node;
          var name = PATH.basename(path);
          var node = FS.lookupNode(parent, name);
          var errCode = FS.mayDelete(parent, name, true);
          if (errCode) throw new FS.ErrnoError(errCode);
          if (!parent.node_ops.rmdir) throw new FS.ErrnoError(63);
          if (FS.isMountpoint(node)) throw new FS.ErrnoError(10);
          parent.node_ops.rmdir(parent, name);
          FS.destroyNode(node);
        },
        readdir(path) {
          var node = FS.lookupPath(path, {
            follow: true
          }).node;
          return FS.checkOpExists(node.node_ops.readdir, 54)(node);
        },
        unlink(path) {
          var parent = FS.lookupPath(path, {
            parent: true
          }).node;
          if (!parent) throw new FS.ErrnoError(44);
          var name = PATH.basename(path);
          var node = FS.lookupNode(parent, name);
          var errCode = FS.mayDelete(parent, name, false);
          if (errCode) throw new FS.ErrnoError(errCode);
          if (!parent.node_ops.unlink) throw new FS.ErrnoError(63);
          if (FS.isMountpoint(node)) throw new FS.ErrnoError(10);
          parent.node_ops.unlink(parent, name);
          FS.destroyNode(node);
        },
        readlink(path) {
          var link = FS.lookupPath(path).node;
          if (!link) throw new FS.ErrnoError(44);
          if (!link.node_ops.readlink) throw new FS.ErrnoError(28);
          return link.node_ops.readlink(link);
        },
        stat(path, dontFollow) {
          var node = FS.lookupPath(path, {
            follow: !dontFollow
          }).node;
          return FS.checkOpExists(node.node_ops.getattr, 63)(node);
        },
        fstat(fd) {
          var stream = FS.getStreamChecked(fd);
          var node = stream.node;
          var getattr = stream.stream_ops.getattr;
          var arg = getattr ? stream : node;
          getattr ??= node.node_ops.getattr;
          FS.checkOpExists(getattr, 63);
          return getattr(arg);
        },
        lstat(path) {
          return FS.stat(path, true);
        },
        doChmod(stream, node, mode, dontFollow) {
          FS.doSetAttr(stream, node, {
            mode: mode & 4095 | node.mode & -4096,
            ctime: Date.now(),
            dontFollow
          });
        },
        chmod(path, mode, dontFollow) {
          var node;
          if (typeof path == "string") node = FS.lookupPath(path, {
            follow: !dontFollow
          }).node;else node = path;
          FS.doChmod(null, node, mode, dontFollow);
        },
        lchmod(path, mode) {
          FS.chmod(path, mode, true);
        },
        fchmod(fd, mode) {
          var stream = FS.getStreamChecked(fd);
          FS.doChmod(stream, stream.node, mode, false);
        },
        doChown(stream, node, dontFollow) {
          FS.doSetAttr(stream, node, {
            timestamp: Date.now(),
            dontFollow
          });
        },
        chown(path, uid, gid, dontFollow) {
          var node;
          if (typeof path == "string") node = FS.lookupPath(path, {
            follow: !dontFollow
          }).node;else node = path;
          FS.doChown(null, node, dontFollow);
        },
        lchown(path, uid, gid) {
          FS.chown(path, uid, gid, true);
        },
        fchown(fd, uid, gid) {
          var stream = FS.getStreamChecked(fd);
          FS.doChown(stream, stream.node, false);
        },
        doTruncate(stream, node, len) {
          if (FS.isDir(node.mode)) throw new FS.ErrnoError(31);
          if (!FS.isFile(node.mode)) throw new FS.ErrnoError(28);
          var errCode = FS.nodePermissions(node, "w");
          if (errCode) throw new FS.ErrnoError(errCode);
          FS.doSetAttr(stream, node, {
            size: len,
            timestamp: Date.now()
          });
        },
        truncate(path, len) {
          if (len < 0) throw new FS.ErrnoError(28);
          var node;
          if (typeof path == "string") node = FS.lookupPath(path, {
            follow: true
          }).node;else node = path;
          FS.doTruncate(null, node, len);
        },
        ftruncate(fd, len) {
          var stream = FS.getStreamChecked(fd);
          if (len < 0 || (stream.flags & 2097155) === 0) throw new FS.ErrnoError(28);
          FS.doTruncate(stream, stream.node, len);
        },
        utime(path, atime, mtime) {
          var node = FS.lookupPath(path, {
            follow: true
          }).node;
          FS.checkOpExists(node.node_ops.setattr, 63)(node, {
            atime,
            mtime
          });
        },
        open(path, flags, mode = 438) {
          if (path === "") throw new FS.ErrnoError(44);
          flags = typeof flags == "string" ? FS_modeStringToFlags(flags) : flags;
          if (flags & 64) mode = mode & 4095 | 32768;else mode = 0;
          var node;
          var isDirPath;
          if (typeof path == "object") node = path;else {
            isDirPath = path.endsWith("/");
            var lookup = FS.lookupPath(path, {
              follow: !(flags & 131072),
              noent_okay: true
            });
            node = lookup.node;
            path = lookup.path;
          }
          var created = false;
          if (flags & 64) if (node) {
            if (flags & 128) throw new FS.ErrnoError(20);
          } else if (isDirPath) throw new FS.ErrnoError(31);else {
            node = FS.mknod(path, mode | 511, 0);
            created = true;
          }
          if (!node) throw new FS.ErrnoError(44);
          if (FS.isChrdev(node.mode)) flags &= -513;
          if (flags & 65536 && !FS.isDir(node.mode)) throw new FS.ErrnoError(54);
          if (!created) {
            var errCode = FS.mayOpen(node, flags);
            if (errCode) throw new FS.ErrnoError(errCode);
          }
          if (flags & 512 && !created) FS.truncate(node, 0);
          flags &= -131713;
          var stream = FS.createStream({
            node,
            path: FS.getPath(node),
            flags,
            seekable: true,
            position: 0,
            stream_ops: node.stream_ops,
            ungotten: [],
            error: false
          });
          if (stream.stream_ops.open) stream.stream_ops.open(stream);
          if (created) FS.chmod(node, mode & 511);
          if (Module["logReadFiles"] && !(flags & 1)) {
            if (!(path in FS.readFiles)) FS.readFiles[path] = 1;
          }
          return stream;
        },
        close(stream) {
          if (FS.isClosed(stream)) throw new FS.ErrnoError(8);
          if (stream.getdents) stream.getdents = null;
          try {
            if (stream.stream_ops.close) stream.stream_ops.close(stream);
          } catch (e) {
            throw e;
          } finally {
            FS.closeStream(stream.fd);
          }
          stream.fd = null;
        },
        isClosed(stream) {
          return stream.fd === null;
        },
        llseek(stream, offset, whence) {
          if (FS.isClosed(stream)) throw new FS.ErrnoError(8);
          if (!stream.seekable || !stream.stream_ops.llseek) throw new FS.ErrnoError(70);
          if (whence != 0 && whence != 1 && whence != 2) throw new FS.ErrnoError(28);
          stream.position = stream.stream_ops.llseek(stream, offset, whence);
          stream.ungotten = [];
          return stream.position;
        },
        read(stream, buffer, offset, length, position) {
          if (length < 0 || position < 0) throw new FS.ErrnoError(28);
          if (FS.isClosed(stream)) throw new FS.ErrnoError(8);
          if ((stream.flags & 2097155) === 1) throw new FS.ErrnoError(8);
          if (FS.isDir(stream.node.mode)) throw new FS.ErrnoError(31);
          if (!stream.stream_ops.read) throw new FS.ErrnoError(28);
          var seeking = typeof position != "undefined";
          if (!seeking) position = stream.position;else if (!stream.seekable) throw new FS.ErrnoError(70);
          var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
          if (!seeking) stream.position += bytesRead;
          return bytesRead;
        },
        write(stream, buffer, offset, length, position, canOwn) {
          if (length < 0 || position < 0) throw new FS.ErrnoError(28);
          if (FS.isClosed(stream)) throw new FS.ErrnoError(8);
          if ((stream.flags & 2097155) === 0) throw new FS.ErrnoError(8);
          if (FS.isDir(stream.node.mode)) throw new FS.ErrnoError(31);
          if (!stream.stream_ops.write) throw new FS.ErrnoError(28);
          if (stream.seekable && stream.flags & 1024) FS.llseek(stream, 0, 2);
          var seeking = typeof position != "undefined";
          if (!seeking) position = stream.position;else if (!stream.seekable) throw new FS.ErrnoError(70);
          var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
          if (!seeking) stream.position += bytesWritten;
          return bytesWritten;
        },
        mmap(stream, length, position, prot, flags) {
          if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) throw new FS.ErrnoError(2);
          if ((stream.flags & 2097155) === 1) throw new FS.ErrnoError(2);
          if (!stream.stream_ops.mmap) throw new FS.ErrnoError(43);
          if (!length) throw new FS.ErrnoError(28);
          return stream.stream_ops.mmap(stream, length, position, prot, flags);
        },
        msync(stream, buffer, offset, length, mmapFlags) {
          if (!stream.stream_ops.msync) return 0;
          return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags);
        },
        ioctl(stream, cmd, arg) {
          if (!stream.stream_ops.ioctl) throw new FS.ErrnoError(59);
          return stream.stream_ops.ioctl(stream, cmd, arg);
        },
        readFile(path, opts = {}) {
          opts.flags = opts.flags || 0;
          opts.encoding = opts.encoding || "binary";
          if (opts.encoding !== "utf8" && opts.encoding !== "binary") abort(`Invalid encoding type "${opts.encoding}"`);
          var stream = FS.open(path, opts.flags);
          var length = FS.stat(path).size;
          var buf = new Uint8Array(length);
          FS.read(stream, buf, 0, length, 0);
          if (opts.encoding === "utf8") buf = UTF8ArrayToString(buf);
          FS.close(stream);
          return buf;
        },
        writeFile(path, data, opts = {}) {
          opts.flags = opts.flags || 577;
          var stream = FS.open(path, opts.flags, opts.mode);
          if (typeof data == "string") data = new Uint8Array(intArrayFromString(data));
          if (ArrayBuffer.isView(data)) FS.write(stream, data, 0, data.byteLength, void 0, opts.canOwn);else abort("Unsupported data type");
          FS.close(stream);
        },
        cwd: () => FS.currentPath,
        chdir(path) {
          var lookup = FS.lookupPath(path, {
            follow: true
          });
          if (lookup.node === null) throw new FS.ErrnoError(44);
          if (!FS.isDir(lookup.node.mode)) throw new FS.ErrnoError(54);
          var errCode = FS.nodePermissions(lookup.node, "x");
          if (errCode) throw new FS.ErrnoError(errCode);
          FS.currentPath = lookup.path;
        },
        createDefaultDirectories() {
          FS.mkdir("/tmp");
          FS.mkdir("/home");
          FS.mkdir("/home/web_user");
        },
        createDefaultDevices() {
          FS.mkdir("/dev");
          FS.registerDevice(FS.makedev(1, 3), {
            read: () => 0,
            write: (stream, buffer, offset, length, pos) => length,
            llseek: () => 0
          });
          FS.mkdev("/dev/null", FS.makedev(1, 3));
          TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
          TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
          FS.mkdev("/dev/tty", FS.makedev(5, 0));
          FS.mkdev("/dev/tty1", FS.makedev(6, 0));
          var randomBuffer = new Uint8Array(1024),
            randomLeft = 0;
          var randomByte = () => {
            if (randomLeft === 0) {
              randomFill(randomBuffer);
              randomLeft = randomBuffer.byteLength;
            }
            return randomBuffer[--randomLeft];
          };
          FS.createDevice("/dev", "random", randomByte);
          FS.createDevice("/dev", "urandom", randomByte);
          FS.mkdir("/dev/shm");
          FS.mkdir("/dev/shm/tmp");
        },
        createSpecialDirectories() {
          FS.mkdir("/proc");
          var proc_self = FS.mkdir("/proc/self");
          FS.mkdir("/proc/self/fd");
          FS.mount({
            mount() {
              var node = FS.createNode(proc_self, "fd", 16895, 73);
              node.stream_ops = {
                llseek: MEMFS.stream_ops.llseek
              };
              node.node_ops = {
                lookup(parent, name) {
                  var fd = +name;
                  var stream = FS.getStreamChecked(fd);
                  var ret = {
                    parent: null,
                    mount: {
                      mountpoint: "fake"
                    },
                    node_ops: {
                      readlink: () => stream.path
                    },
                    id: fd + 1
                  };
                  ret.parent = ret;
                  return ret;
                },
                readdir() {
                  return Array.from(FS.streams.entries()).filter(([k, v]) => v).map(([k, v]) => k.toString());
                }
              };
              return node;
            }
          }, {}, "/proc/self/fd");
        },
        createStandardStreams(input, output, error) {
          if (input) FS.createDevice("/dev", "stdin", input);else FS.symlink("/dev/tty", "/dev/stdin");
          if (output) FS.createDevice("/dev", "stdout", null, output);else FS.symlink("/dev/tty", "/dev/stdout");
          if (error) FS.createDevice("/dev", "stderr", null, error);else FS.symlink("/dev/tty1", "/dev/stderr");
          FS.open("/dev/stdin", 0);
          FS.open("/dev/stdout", 1);
          FS.open("/dev/stderr", 1);
        },
        staticInit() {
          FS.nameTable = new Array(4096);
          FS.mount(MEMFS, {}, "/");
          FS.createDefaultDirectories();
          FS.createDefaultDevices();
          FS.createSpecialDirectories();
          FS.filesystems = {
            "MEMFS": MEMFS
          };
        },
        init(input, output, error) {
          FS.initialized = true;
          input ??= Module["stdin"];
          output ??= Module["stdout"];
          error ??= Module["stderr"];
          FS.createStandardStreams(input, output, error);
        },
        quit() {
          FS.initialized = false;
          for (var stream of FS.streams) if (stream) FS.close(stream);
        },
        findObject(path, dontResolveLastLink) {
          var ret = FS.analyzePath(path, dontResolveLastLink);
          if (!ret.exists) return null;
          return ret.object;
        },
        analyzePath(path, dontResolveLastLink) {
          try {
            var lookup = FS.lookupPath(path, {
              follow: !dontResolveLastLink
            });
            path = lookup.path;
          } catch (e) {}
          var ret = {
            isRoot: false,
            exists: false,
            error: 0,
            name: null,
            path: null,
            object: null,
            parentExists: false,
            parentPath: null,
            parentObject: null
          };
          try {
            var lookup = FS.lookupPath(path, {
              parent: true
            });
            ret.parentExists = true;
            ret.parentPath = lookup.path;
            ret.parentObject = lookup.node;
            ret.name = PATH.basename(path);
            lookup = FS.lookupPath(path, {
              follow: !dontResolveLastLink
            });
            ret.exists = true;
            ret.path = lookup.path;
            ret.object = lookup.node;
            ret.name = lookup.node.name;
            ret.isRoot = lookup.path === "/";
          } catch (e) {
            ret.error = e.errno;
          }
          return ret;
        },
        createPath(parent, path, canRead, canWrite) {
          parent = typeof parent == "string" ? parent : FS.getPath(parent);
          var parts = path.split("/").reverse();
          while (parts.length) {
            var part = parts.pop();
            if (!part) continue;
            var current = PATH.join2(parent, part);
            try {
              FS.mkdir(current);
            } catch (e) {
              if (e.errno != 20) throw e;
            }
            parent = current;
          }
          return current;
        },
        createFile(parent, name, properties, canRead, canWrite) {
          var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name);
          var mode = FS_getMode(canRead, canWrite);
          return FS.create(path, mode);
        },
        createDataFile(parent, name, data, canRead, canWrite, canOwn) {
          var path = name;
          if (parent) {
            parent = typeof parent == "string" ? parent : FS.getPath(parent);
            path = name ? PATH.join2(parent, name) : parent;
          }
          var mode = FS_getMode(canRead, canWrite);
          var node = FS.create(path, mode);
          if (data) {
            if (typeof data == "string") {
              var arr = new Array(data.length);
              for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
              data = arr;
            }
            FS.chmod(node, mode | 146);
            var stream = FS.open(node, 577);
            FS.write(stream, data, 0, data.length, 0, canOwn);
            FS.close(stream);
            FS.chmod(node, mode);
          }
        },
        createDevice(parent, name, input, output) {
          var path = PATH.join2(typeof parent == "string" ? parent : FS.getPath(parent), name);
          var mode = FS_getMode(!!input, !!output);
          FS.createDevice.major ??= 64;
          var dev = FS.makedev(FS.createDevice.major++, 0);
          FS.registerDevice(dev, {
            open(stream) {
              stream.seekable = false;
            },
            close(stream) {
              if (output?.buffer?.length) output(10);
            },
            read(stream, buffer, offset, length, pos) {
              var bytesRead = 0;
              for (var i = 0; i < length; i++) {
                var result;
                try {
                  result = input();
                } catch (e) {
                  throw new FS.ErrnoError(29);
                }
                if (result === void 0 && bytesRead === 0) throw new FS.ErrnoError(6);
                if (result === null || result === void 0) break;
                bytesRead++;
                buffer[offset + i] = result;
              }
              if (bytesRead) stream.node.atime = Date.now();
              return bytesRead;
            },
            write(stream, buffer, offset, length, pos) {
              for (var i = 0; i < length; i++) try {
                output(buffer[offset + i]);
              } catch (e) {
                throw new FS.ErrnoError(29);
              }
              if (length) stream.node.mtime = stream.node.ctime = Date.now();
              return i;
            }
          });
          return FS.mkdev(path, mode, dev);
        },
        forceLoadFile(obj) {
          if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
          if (globalThis.XMLHttpRequest) abort("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");else try {
            obj.contents = readBinary(obj.url);
          } catch (e) {
            throw new FS.ErrnoError(29);
          }
        },
        createLazyFile(parent, name, url, canRead, canWrite) {
          class LazyUint8Array {
            lengthKnown = false;
            chunks = [];
            get(idx) {
              if (idx > this.length - 1 || idx < 0) return;
              var chunkOffset = idx % this.chunkSize;
              var chunkNum = idx / this.chunkSize | 0;
              return this.getter(chunkNum)[chunkOffset];
            }
            setDataGetter(getter) {
              this.getter = getter;
            }
            cacheLength() {
              var xhr = new XMLHttpRequest();
              xhr.open("HEAD", url, false);
              xhr.send(null);
              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status);
              var datalength = Number(xhr.getResponseHeader("Content-length"));
              var header;
              var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
              var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip";
              var chunkSize = 1024 * 1024;
              if (!hasByteServing) chunkSize = datalength;
              var doXHR = (from, to) => {
                if (from > to) abort("invalid range (" + from + ", " + to + ") or no bytes requested!");
                if (to > datalength - 1) abort("only " + datalength + " bytes available! programmer error!");
                var xhr = new XMLHttpRequest();
                xhr.open("GET", url, false);
                if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
                xhr.responseType = "arraybuffer";
                if (xhr.overrideMimeType) xhr.overrideMimeType("text/plain; charset=x-user-defined");
                xhr.send(null);
                if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status);
                if (xhr.response !== void 0) return new Uint8Array(xhr.response || []);
                return intArrayFromString(xhr.responseText || "");
              };
              var lazyArray = this;
              lazyArray.setDataGetter(chunkNum => {
                var start = chunkNum * chunkSize;
                var end = (chunkNum + 1) * chunkSize - 1;
                end = Math.min(end, datalength - 1);
                if (typeof lazyArray.chunks[chunkNum] == "undefined") lazyArray.chunks[chunkNum] = doXHR(start, end);
                if (typeof lazyArray.chunks[chunkNum] == "undefined") abort("doXHR failed!");
                return lazyArray.chunks[chunkNum];
              });
              if (usesGzip || !datalength) {
                chunkSize = datalength = 1;
                datalength = this.getter(0).length;
                chunkSize = datalength;
                out("LazyFiles on gzip forces download of the whole file when length is accessed");
              }
              this._length = datalength;
              this._chunkSize = chunkSize;
              this.lengthKnown = true;
            }
            get length() {
              if (!this.lengthKnown) this.cacheLength();
              return this._length;
            }
            get chunkSize() {
              if (!this.lengthKnown) this.cacheLength();
              return this._chunkSize;
            }
          }
          if (globalThis.XMLHttpRequest) {
            if (!ENVIRONMENT_IS_WORKER) abort("Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc");
            var properties = {
              isDevice: false,
              contents: new LazyUint8Array()
            };
          } else var properties = {
            isDevice: false,
            url
          };
          var node = FS.createFile(parent, name, properties, canRead, canWrite);
          if (properties.contents) node.contents = properties.contents;else if (properties.url) {
            node.contents = null;
            node.url = properties.url;
          }
          Object.defineProperties(node, {
            usedBytes: {
              get: function () {
                return this.contents.length;
              }
            }
          });
          var stream_ops = {};
          for (const [key, fn] of Object.entries(node.stream_ops)) stream_ops[key] = (...args) => {
            FS.forceLoadFile(node);
            return fn(...args);
          };
          function writeChunks(stream, buffer, offset, length, position) {
            var contents = stream.node.contents;
            if (position >= contents.length) return 0;
            var size = Math.min(contents.length - position, length);
            if (contents.slice) for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];else for (var i = 0; i < size; i++) buffer[offset + i] = contents.get(position + i);
            return size;
          }
          stream_ops.read = (stream, buffer, offset, length, position) => {
            FS.forceLoadFile(node);
            return writeChunks(stream, buffer, offset, length, position);
          };
          stream_ops.mmap = (stream, length, position, prot, flags) => {
            FS.forceLoadFile(node);
            var ptr = mmapAlloc(length);
            if (!ptr) throw new FS.ErrnoError(48);
            writeChunks(stream, HEAP8, ptr, length, position);
            return {
              ptr,
              allocated: true
            };
          };
          node.stream_ops = stream_ops;
          return node;
        }
      };
      var UTF8ToString = (ptr, maxBytesToRead, ignoreNul) => {
        if (!ptr) return "";
        var end = findStringEnd(HEAPU8, ptr, maxBytesToRead);
        return UTF8Decoder.decode(HEAPU8.subarray(ptr, end));
      };
      var SYSCALLS = {
        calculateAt(dirfd, path, allowEmpty) {
          if (PATH.isAbs(path)) return path;
          var dir;
          if (dirfd === -100) dir = FS.cwd();else dir = SYSCALLS.getStreamFromFD(dirfd).path;
          if (path.length == 0) {
            if (!allowEmpty) throw new FS.ErrnoError(44);
            return dir;
          }
          return dir + "/" + path;
        },
        writeStat(buf, stat) {
          HEAPU32[buf >> 2] = stat.dev;
          HEAPU32[buf + 4 >> 2] = stat.mode;
          HEAPU32[buf + 8 >> 2] = stat.nlink;
          HEAPU32[buf + 12 >> 2] = stat.uid;
          HEAPU32[buf + 16 >> 2] = stat.gid;
          HEAPU32[buf + 20 >> 2] = stat.rdev;
          HEAP64[buf + 24 >> 3] = BigInt(stat.size);
          HEAP32[buf + 32 >> 2] = 4096;
          HEAP32[buf + 36 >> 2] = stat.blocks;
          var atime = stat.atime.getTime();
          var mtime = stat.mtime.getTime();
          var ctime = stat.ctime.getTime();
          HEAP64[buf + 40 >> 3] = BigInt(Math.floor(atime / 1e3));
          HEAPU32[buf + 48 >> 2] = atime % 1e3 * 1e3 * 1e3;
          HEAP64[buf + 56 >> 3] = BigInt(Math.floor(mtime / 1e3));
          HEAPU32[buf + 64 >> 2] = mtime % 1e3 * 1e3 * 1e3;
          HEAP64[buf + 72 >> 3] = BigInt(Math.floor(ctime / 1e3));
          HEAPU32[buf + 80 >> 2] = ctime % 1e3 * 1e3 * 1e3;
          HEAP64[buf + 88 >> 3] = BigInt(stat.ino);
          return 0;
        },
        writeStatFs(buf, stats) {
          HEAPU32[buf + 4 >> 2] = stats.bsize;
          HEAPU32[buf + 60 >> 2] = stats.bsize;
          HEAP64[buf + 8 >> 3] = BigInt(stats.blocks);
          HEAP64[buf + 16 >> 3] = BigInt(stats.bfree);
          HEAP64[buf + 24 >> 3] = BigInt(stats.bavail);
          HEAP64[buf + 32 >> 3] = BigInt(stats.files);
          HEAP64[buf + 40 >> 3] = BigInt(stats.ffree);
          HEAPU32[buf + 48 >> 2] = stats.fsid;
          HEAPU32[buf + 64 >> 2] = stats.flags;
          HEAPU32[buf + 56 >> 2] = stats.namelen;
        },
        doMsync(addr, stream, len, flags, offset) {
          if (!FS.isFile(stream.node.mode)) throw new FS.ErrnoError(43);
          if (flags & 2) return 0;
          var buffer = HEAPU8.slice(addr, addr + len);
          FS.msync(stream, buffer, offset, len, flags);
        },
        getStreamFromFD(fd) {
          return FS.getStreamChecked(fd);
        },
        varargs: void 0,
        getStr(ptr) {
          return UTF8ToString(ptr);
        }
      };
      function ___syscall_chmod(path, mode) {
        try {
          path = SYSCALLS.getStr(path);
          FS.chmod(path, mode);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_faccessat(dirfd, path, amode, flags) {
        try {
          path = SYSCALLS.getStr(path);
          path = SYSCALLS.calculateAt(dirfd, path);
          if (amode & -8) return -28;
          var node = FS.lookupPath(path, {
            follow: true
          }).node;
          if (!node) return -44;
          var perms = "";
          if (amode & 4) perms += "r";
          if (amode & 2) perms += "w";
          if (amode & 1) perms += "x";
          if (perms && FS.nodePermissions(node, perms)) return -2;
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_fchmod(fd, mode) {
        try {
          FS.fchmod(fd, mode);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_fchown32(fd, owner, group) {
        try {
          FS.fchown(fd, owner, group);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      var syscallGetVarargI = () => {
        var ret = HEAP32[+SYSCALLS.varargs >> 2];
        SYSCALLS.varargs += 4;
        return ret;
      };
      var syscallGetVarargP = syscallGetVarargI;
      function ___syscall_fcntl64(fd, cmd, varargs) {
        SYSCALLS.varargs = varargs;
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          switch (cmd) {
            case 0:
              var arg = syscallGetVarargI();
              if (arg < 0) return -28;
              while (FS.streams[arg]) arg++;
              return FS.dupStream(stream, arg).fd;
            case 1:
            case 2:
              return 0;
            case 3:
              return stream.flags;
            case 4:
              var arg = syscallGetVarargI();
              stream.flags |= arg;
              return 0;
            case 12:
              var arg = syscallGetVarargP();
              var offset = 0;
              HEAP16[arg + offset >> 1] = 2;
              return 0;
            case 13:
            case 14:
              return 0;
          }
          return -28;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_fstat64(fd, buf) {
        try {
          return SYSCALLS.writeStat(buf, FS.fstat(fd));
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      var INT53_MAX = 9007199254740992;
      var INT53_MIN = -9007199254740992;
      var bigintToI53Checked = num => num < INT53_MIN || num > INT53_MAX ? NaN : Number(num);
      function ___syscall_ftruncate64(fd, length) {
        length = bigintToI53Checked(length);
        try {
          if (isNaN(length)) return -61;
          FS.ftruncate(fd, length);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      var stringToUTF8 = (str, outPtr, maxBytesToWrite) => {
        return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
      };
      function ___syscall_getcwd(buf, size) {
        try {
          if (size === 0) return -28;
          var cwd = FS.cwd();
          var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1;
          if (size < cwdLengthInBytes) return -68;
          stringToUTF8(cwd, buf, size);
          return cwdLengthInBytes;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_ioctl(fd, op, varargs) {
        SYSCALLS.varargs = varargs;
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          switch (op) {
            case 21509:
              if (!stream.tty) return -59;
              return 0;
            case 21505:
              if (!stream.tty) return -59;
              if (stream.tty.ops.ioctl_tcgets) {
                var termios = stream.tty.ops.ioctl_tcgets(stream);
                var argp = syscallGetVarargP();
                HEAP32[argp >> 2] = termios.c_iflag || 0;
                HEAP32[argp + 4 >> 2] = termios.c_oflag || 0;
                HEAP32[argp + 8 >> 2] = termios.c_cflag || 0;
                HEAP32[argp + 12 >> 2] = termios.c_lflag || 0;
                for (var i = 0; i < 32; i++) HEAP8[argp + i + 17] = termios.c_cc[i] || 0;
                return 0;
              }
              return 0;
            case 21510:
            case 21511:
            case 21512:
              if (!stream.tty) return -59;
              return 0;
            case 21506:
            case 21507:
            case 21508:
              if (!stream.tty) return -59;
              if (stream.tty.ops.ioctl_tcsets) {
                var argp = syscallGetVarargP();
                var c_iflag = HEAP32[argp >> 2];
                var c_oflag = HEAP32[argp + 4 >> 2];
                var c_cflag = HEAP32[argp + 8 >> 2];
                var c_lflag = HEAP32[argp + 12 >> 2];
                var c_cc = [];
                for (var i = 0; i < 32; i++) c_cc.push(HEAP8[argp + i + 17]);
                return stream.tty.ops.ioctl_tcsets(stream.tty, op, {
                  c_iflag,
                  c_oflag,
                  c_cflag,
                  c_lflag,
                  c_cc
                });
              }
              return 0;
            case 21519:
              if (!stream.tty) return -59;
              var argp = syscallGetVarargP();
              HEAP32[argp >> 2] = 0;
              return 0;
            case 21520:
              if (!stream.tty) return -59;
              return -28;
            case 21537:
            case 21531:
              var argp = syscallGetVarargP();
              return FS.ioctl(stream, op, argp);
            case 21523:
              if (!stream.tty) return -59;
              if (stream.tty.ops.ioctl_tiocgwinsz) {
                var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty);
                var argp = syscallGetVarargP();
                HEAP16[argp >> 1] = winsize[0];
                HEAP16[argp + 2 >> 1] = winsize[1];
              }
              return 0;
            case 21524:
              if (!stream.tty) return -59;
              return 0;
            case 21515:
              if (!stream.tty) return -59;
              return 0;
            default:
              return -28;
          }
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_lstat64(path, buf) {
        try {
          path = SYSCALLS.getStr(path);
          return SYSCALLS.writeStat(buf, FS.lstat(path));
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_mkdirat(dirfd, path, mode) {
        try {
          path = SYSCALLS.getStr(path);
          path = SYSCALLS.calculateAt(dirfd, path);
          FS.mkdir(path, mode, 0);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_newfstatat(dirfd, path, buf, flags) {
        try {
          path = SYSCALLS.getStr(path);
          var nofollow = flags & 256;
          var allowEmpty = flags & 4096;
          flags = flags & -6401;
          path = SYSCALLS.calculateAt(dirfd, path, allowEmpty);
          return SYSCALLS.writeStat(buf, nofollow ? FS.lstat(path) : FS.stat(path));
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_openat(dirfd, path, flags, varargs) {
        SYSCALLS.varargs = varargs;
        try {
          path = SYSCALLS.getStr(path);
          path = SYSCALLS.calculateAt(dirfd, path);
          var mode = varargs ? syscallGetVarargI() : 0;
          return FS.open(path, flags, mode).fd;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_readlinkat(dirfd, path, buf, bufsize) {
        try {
          path = SYSCALLS.getStr(path);
          path = SYSCALLS.calculateAt(dirfd, path);
          if (bufsize <= 0) return -28;
          var ret = FS.readlink(path);
          var len = Math.min(bufsize, lengthBytesUTF8(ret));
          var endChar = HEAP8[buf + len];
          stringToUTF8(ret, buf, bufsize + 1);
          HEAP8[buf + len] = endChar;
          return len;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_rmdir(path) {
        try {
          path = SYSCALLS.getStr(path);
          FS.rmdir(path);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_stat64(path, buf) {
        try {
          path = SYSCALLS.getStr(path);
          return SYSCALLS.writeStat(buf, FS.stat(path));
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function ___syscall_unlinkat(dirfd, path, flags) {
        try {
          path = SYSCALLS.getStr(path);
          path = SYSCALLS.calculateAt(dirfd, path);
          if (!flags) FS.unlink(path);else if (flags === 512) FS.rmdir(path);else return -28;
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      var readI53FromI64 = ptr => {
        return HEAPU32[ptr >> 2] + HEAP32[ptr + 4 >> 2] * 4294967296;
      };
      function ___syscall_utimensat(dirfd, path, times, flags) {
        try {
          path = SYSCALLS.getStr(path);
          path = SYSCALLS.calculateAt(dirfd, path, true);
          var now = Date.now(),
            atime,
            mtime;
          if (!times) {
            atime = now;
            mtime = now;
          } else {
            var seconds = readI53FromI64(times);
            var nanoseconds = HEAP32[times + 8 >> 2];
            if (nanoseconds == 1073741823) atime = now;else if (nanoseconds == 1073741822) atime = null;else atime = seconds * 1e3 + nanoseconds / (1e3 * 1e3);
            times += 16;
            seconds = readI53FromI64(times);
            nanoseconds = HEAP32[times + 8 >> 2];
            if (nanoseconds == 1073741823) mtime = now;else if (nanoseconds == 1073741822) mtime = null;else mtime = seconds * 1e3 + nanoseconds / (1e3 * 1e3);
          }
          if ((mtime ?? atime) !== null) FS.utime(path, atime, mtime);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      var isLeapYear = year => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
      var MONTH_DAYS_LEAP_CUMULATIVE = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335];
      var MONTH_DAYS_REGULAR_CUMULATIVE = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
      var ydayFromDate = date => {
        return (isLeapYear(date.getFullYear()) ? MONTH_DAYS_LEAP_CUMULATIVE : MONTH_DAYS_REGULAR_CUMULATIVE)[date.getMonth()] + date.getDate() - 1;
      };
      function __localtime_js(time, tmPtr) {
        time = bigintToI53Checked(time);
        var date = /* @__PURE__ */new Date(time * 1e3);
        HEAP32[tmPtr >> 2] = date.getSeconds();
        HEAP32[tmPtr + 4 >> 2] = date.getMinutes();
        HEAP32[tmPtr + 8 >> 2] = date.getHours();
        HEAP32[tmPtr + 12 >> 2] = date.getDate();
        HEAP32[tmPtr + 16 >> 2] = date.getMonth();
        HEAP32[tmPtr + 20 >> 2] = date.getFullYear() - 1900;
        HEAP32[tmPtr + 24 >> 2] = date.getDay();
        var yday = ydayFromDate(date) | 0;
        HEAP32[tmPtr + 28 >> 2] = yday;
        HEAP32[tmPtr + 36 >> 2] = -(date.getTimezoneOffset() * 60);
        var start = new Date(date.getFullYear(), 0, 1);
        var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset();
        var winterOffset = start.getTimezoneOffset();
        var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset)) | 0;
        HEAP32[tmPtr + 32 >> 2] = dst;
      }
      function __mmap_js(len, prot, flags, fd, offset, allocated, addr) {
        offset = bigintToI53Checked(offset);
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          var res = FS.mmap(stream, len, offset, prot, flags);
          var ptr = res.ptr;
          HEAP32[allocated >> 2] = res.allocated;
          HEAPU32[addr >> 2] = ptr;
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      function __munmap_js(addr, len, prot, flags, fd, offset) {
        offset = bigintToI53Checked(offset);
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          if (prot & 2) SYSCALLS.doMsync(addr, stream, len, flags, offset);
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return -e.errno;
        }
      }
      var __tzset_js = (timezone, daylight, std_name, dst_name) => {
        var currentYear = (/* @__PURE__ */new Date()).getFullYear();
        var winter = new Date(currentYear, 0, 1);
        var summer = new Date(currentYear, 6, 1);
        var winterOffset = winter.getTimezoneOffset();
        var summerOffset = summer.getTimezoneOffset();
        var stdTimezoneOffset = Math.max(winterOffset, summerOffset);
        HEAPU32[timezone >> 2] = stdTimezoneOffset * 60;
        HEAP32[daylight >> 2] = Number(winterOffset != summerOffset);
        var extractZone = timezoneOffset => {
          var sign = timezoneOffset >= 0 ? "-" : "+";
          var absOffset = Math.abs(timezoneOffset);
          return `UTC${sign}${String(Math.floor(absOffset / 60)).padStart(2, "0")}${String(absOffset % 60).padStart(2, "0")}`;
        };
        var winterName = extractZone(winterOffset);
        var summerName = extractZone(summerOffset);
        if (summerOffset < winterOffset) {
          stringToUTF8(winterName, std_name, 17);
          stringToUTF8(summerName, dst_name, 17);
        } else {
          stringToUTF8(winterName, dst_name, 17);
          stringToUTF8(summerName, std_name, 17);
        }
      };
      var _emscripten_get_now = () => performance.now();
      var _emscripten_date_now = () => Date.now();
      var checkWasiClock = clock_id => clock_id >= 0 && clock_id <= 3;
      function _clock_time_get(clk_id, ignored_precision, ptime) {
        if (!checkWasiClock(clk_id)) return 28;
        var now;
        if (clk_id === 0) now = _emscripten_date_now();else now = _emscripten_get_now();
        var nsec = Math.round(now * 1e3 * 1e3);
        HEAP64[ptime >> 3] = BigInt(nsec);
        return 0;
      }
      var getHeapMax = () => 2147483648;
      var _emscripten_get_heap_max = () => getHeapMax();
      var growMemory = size => {
        var pages = (size - wasmMemory.buffer.byteLength + 65535) / 65536 | 0;
        try {
          wasmMemory.grow(pages);
          updateMemoryViews();
          return 1;
        } catch (e) {}
      };
      var _emscripten_resize_heap = requestedSize => {
        var oldSize = HEAPU8.length;
        requestedSize >>>= 0;
        var maxHeapSize = getHeapMax();
        if (requestedSize > maxHeapSize) return false;
        for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
          var overGrownHeapSize = oldSize * (1 + .2 / cutDown);
          overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
          if (growMemory(Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536)))) return true;
        }
        return false;
      };
      var ENV = {};
      var getExecutableName = () => thisProgram || "./this.program";
      var getEnvStrings = () => {
        if (!getEnvStrings.strings) {
          var lang = (globalThis.navigator?.language ?? "C").replace("-", "_") + ".UTF-8";
          var env = {
            "USER": "web_user",
            "LOGNAME": "web_user",
            "PATH": "/",
            "PWD": "/",
            "HOME": "/home/web_user",
            "LANG": lang,
            "_": getExecutableName()
          };
          for (var x in ENV) if (ENV[x] === void 0) delete env[x];else env[x] = ENV[x];
          var strings = [];
          for (var x in env) strings.push(`${x}=${env[x]}`);
          getEnvStrings.strings = strings;
        }
        return getEnvStrings.strings;
      };
      var _environ_get = (__environ, environ_buf) => {
        var bufSize = 0;
        var envp = 0;
        for (var string of getEnvStrings()) {
          var ptr = environ_buf + bufSize;
          HEAPU32[__environ + envp >> 2] = ptr;
          bufSize += stringToUTF8(string, ptr, Infinity) + 1;
          envp += 4;
        }
        return 0;
      };
      var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
        var strings = getEnvStrings();
        HEAPU32[penviron_count >> 2] = strings.length;
        var bufSize = 0;
        for (var string of strings) bufSize += lengthBytesUTF8(string) + 1;
        HEAPU32[penviron_buf_size >> 2] = bufSize;
        return 0;
      };
      function _fd_close(fd) {
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          FS.close(stream);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno;
        }
      }
      function _fd_fdstat_get(fd, pbuf) {
        try {
          var rightsBase = 0;
          var rightsInheriting = 0;
          var flags = 0;
          var stream = SYSCALLS.getStreamFromFD(fd);
          var type = stream.tty ? 2 : FS.isDir(stream.mode) ? 3 : FS.isLink(stream.mode) ? 7 : 4;
          HEAP8[pbuf] = type;
          HEAP16[pbuf + 2 >> 1] = flags;
          HEAP64[pbuf + 8 >> 3] = BigInt(rightsBase);
          HEAP64[pbuf + 16 >> 3] = BigInt(rightsInheriting);
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno;
        }
      }
      var doReadv = (stream, iov, iovcnt, offset) => {
        var ret = 0;
        for (var i = 0; i < iovcnt; i++) {
          var ptr = HEAPU32[iov >> 2];
          var len = HEAPU32[iov + 4 >> 2];
          iov += 8;
          var curr = FS.read(stream, HEAP8, ptr, len, offset);
          if (curr < 0) return -1;
          ret += curr;
          if (curr < len) break;
        }
        return ret;
      };
      function _fd_read(fd, iov, iovcnt, pnum) {
        try {
          var num = doReadv(SYSCALLS.getStreamFromFD(fd), iov, iovcnt);
          HEAPU32[pnum >> 2] = num;
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno;
        }
      }
      function _fd_seek(fd, offset, whence, newOffset) {
        offset = bigintToI53Checked(offset);
        try {
          if (isNaN(offset)) return 61;
          var stream = SYSCALLS.getStreamFromFD(fd);
          FS.llseek(stream, offset, whence);
          HEAP64[newOffset >> 3] = BigInt(stream.position);
          if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null;
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno;
        }
      }
      function _fd_sync(fd) {
        try {
          var stream = SYSCALLS.getStreamFromFD(fd);
          return stream.stream_ops?.fsync?.(stream);
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno;
        }
      }
      var doWritev = (stream, iov, iovcnt, offset) => {
        var ret = 0;
        for (var i = 0; i < iovcnt; i++) {
          var ptr = HEAPU32[iov >> 2];
          var len = HEAPU32[iov + 4 >> 2];
          iov += 8;
          var curr = FS.write(stream, HEAP8, ptr, len, offset);
          if (curr < 0) return -1;
          ret += curr;
          if (curr < len) break;
        }
        return ret;
      };
      function _fd_write(fd, iov, iovcnt, pnum) {
        try {
          var num = doWritev(SYSCALLS.getStreamFromFD(fd), iov, iovcnt);
          HEAPU32[pnum >> 2] = num;
          return 0;
        } catch (e) {
          if (typeof FS == "undefined" || !(e.name === "ErrnoError")) throw e;
          return e.errno;
        }
      }
      FS.createPreloadedFile = FS_createPreloadedFile;
      FS.preloadFile = FS_preloadFile;
      FS.staticInit();
      initMemory();
      if (Module["noExitRuntime"]) Module["noExitRuntime"];
      if (Module["preloadPlugins"]) preloadPlugins = Module["preloadPlugins"];
      if (Module["print"]) out = Module["print"];
      if (Module["printErr"]) err = Module["printErr"];
      if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"];
      if (Module["arguments"]) Module["arguments"];
      if (Module["thisProgram"]) thisProgram = Module["thisProgram"];
      if (Module["preInit"]) {
        if (typeof Module["preInit"] == "function") Module["preInit"] = [Module["preInit"]];
        while (Module["preInit"].length > 0) Module["preInit"].shift()();
      }
      Module["wasmMemory"] = wasmMemory;
      var _emscripten_builtin_memalign;
      function assignWasmExports(wasmExports) {
        Module["_sqlite3_status64"] = wasmExports["sqlite3_status64"];
        Module["_sqlite3_status"] = wasmExports["sqlite3_status"];
        Module["_sqlite3_db_status64"] = wasmExports["sqlite3_db_status64"];
        Module["_sqlite3_msize"] = wasmExports["sqlite3_msize"];
        Module["_sqlite3_db_status"] = wasmExports["sqlite3_db_status"];
        Module["_sqlite3_vfs_find"] = wasmExports["sqlite3_vfs_find"];
        Module["_sqlite3_initialize"] = wasmExports["sqlite3_initialize"];
        Module["_sqlite3_malloc"] = wasmExports["sqlite3_malloc"];
        Module["_sqlite3_free"] = wasmExports["sqlite3_free"];
        Module["_sqlite3_vfs_register"] = wasmExports["sqlite3_vfs_register"];
        Module["_sqlite3_vfs_unregister"] = wasmExports["sqlite3_vfs_unregister"];
        Module["_sqlite3_malloc64"] = wasmExports["sqlite3_malloc64"];
        Module["_sqlite3_realloc"] = wasmExports["sqlite3_realloc"];
        Module["_sqlite3_realloc64"] = wasmExports["sqlite3_realloc64"];
        Module["_sqlite3_value_text"] = wasmExports["sqlite3_value_text"];
        Module["_sqlite3_randomness"] = wasmExports["sqlite3_randomness"];
        Module["_sqlite3_stricmp"] = wasmExports["sqlite3_stricmp"];
        Module["_sqlite3_strnicmp"] = wasmExports["sqlite3_strnicmp"];
        Module["_sqlite3_uri_parameter"] = wasmExports["sqlite3_uri_parameter"];
        Module["_sqlite3_uri_boolean"] = wasmExports["sqlite3_uri_boolean"];
        Module["_sqlite3_serialize"] = wasmExports["sqlite3_serialize"];
        Module["_sqlite3_prepare_v2"] = wasmExports["sqlite3_prepare_v2"];
        Module["_sqlite3_step"] = wasmExports["sqlite3_step"];
        Module["_sqlite3_column_int64"] = wasmExports["sqlite3_column_int64"];
        Module["_sqlite3_reset"] = wasmExports["sqlite3_reset"];
        Module["_sqlite3_exec"] = wasmExports["sqlite3_exec"];
        Module["_sqlite3_column_int"] = wasmExports["sqlite3_column_int"];
        Module["_sqlite3_finalize"] = wasmExports["sqlite3_finalize"];
        Module["_sqlite3_file_control"] = wasmExports["sqlite3_file_control"];
        Module["_sqlite3_column_name"] = wasmExports["sqlite3_column_name"];
        Module["_sqlite3_column_text"] = wasmExports["sqlite3_column_text"];
        Module["_sqlite3_column_type"] = wasmExports["sqlite3_column_type"];
        Module["_sqlite3_errmsg"] = wasmExports["sqlite3_errmsg"];
        Module["_sqlite3_deserialize"] = wasmExports["sqlite3_deserialize"];
        Module["_sqlite3_clear_bindings"] = wasmExports["sqlite3_clear_bindings"];
        Module["_sqlite3_value_blob"] = wasmExports["sqlite3_value_blob"];
        Module["_sqlite3_value_bytes"] = wasmExports["sqlite3_value_bytes"];
        Module["_sqlite3_value_double"] = wasmExports["sqlite3_value_double"];
        Module["_sqlite3_value_int"] = wasmExports["sqlite3_value_int"];
        Module["_sqlite3_value_int64"] = wasmExports["sqlite3_value_int64"];
        Module["_sqlite3_value_subtype"] = wasmExports["sqlite3_value_subtype"];
        Module["_sqlite3_value_pointer"] = wasmExports["sqlite3_value_pointer"];
        Module["_sqlite3_value_type"] = wasmExports["sqlite3_value_type"];
        Module["_sqlite3_value_nochange"] = wasmExports["sqlite3_value_nochange"];
        Module["_sqlite3_value_frombind"] = wasmExports["sqlite3_value_frombind"];
        Module["_sqlite3_value_dup"] = wasmExports["sqlite3_value_dup"];
        Module["_sqlite3_value_free"] = wasmExports["sqlite3_value_free"];
        Module["_sqlite3_result_blob"] = wasmExports["sqlite3_result_blob"];
        Module["_sqlite3_result_error_toobig"] = wasmExports["sqlite3_result_error_toobig"];
        Module["_sqlite3_result_error_nomem"] = wasmExports["sqlite3_result_error_nomem"];
        Module["_sqlite3_result_double"] = wasmExports["sqlite3_result_double"];
        Module["_sqlite3_result_error"] = wasmExports["sqlite3_result_error"];
        Module["_sqlite3_result_int"] = wasmExports["sqlite3_result_int"];
        Module["_sqlite3_result_int64"] = wasmExports["sqlite3_result_int64"];
        Module["_sqlite3_result_null"] = wasmExports["sqlite3_result_null"];
        Module["_sqlite3_result_pointer"] = wasmExports["sqlite3_result_pointer"];
        Module["_sqlite3_result_subtype"] = wasmExports["sqlite3_result_subtype"];
        Module["_sqlite3_result_text"] = wasmExports["sqlite3_result_text"];
        Module["_sqlite3_result_zeroblob"] = wasmExports["sqlite3_result_zeroblob"];
        Module["_sqlite3_result_zeroblob64"] = wasmExports["sqlite3_result_zeroblob64"];
        Module["_sqlite3_result_error_code"] = wasmExports["sqlite3_result_error_code"];
        Module["_sqlite3_user_data"] = wasmExports["sqlite3_user_data"];
        Module["_sqlite3_context_db_handle"] = wasmExports["sqlite3_context_db_handle"];
        Module["_sqlite3_vtab_nochange"] = wasmExports["sqlite3_vtab_nochange"];
        Module["_sqlite3_vtab_in_first"] = wasmExports["sqlite3_vtab_in_first"];
        Module["_sqlite3_vtab_in_next"] = wasmExports["sqlite3_vtab_in_next"];
        Module["_sqlite3_aggregate_context"] = wasmExports["sqlite3_aggregate_context"];
        Module["_sqlite3_get_auxdata"] = wasmExports["sqlite3_get_auxdata"];
        Module["_sqlite3_set_auxdata"] = wasmExports["sqlite3_set_auxdata"];
        Module["_sqlite3_column_count"] = wasmExports["sqlite3_column_count"];
        Module["_sqlite3_data_count"] = wasmExports["sqlite3_data_count"];
        Module["_sqlite3_column_blob"] = wasmExports["sqlite3_column_blob"];
        Module["_sqlite3_column_bytes"] = wasmExports["sqlite3_column_bytes"];
        Module["_sqlite3_column_double"] = wasmExports["sqlite3_column_double"];
        Module["_sqlite3_column_value"] = wasmExports["sqlite3_column_value"];
        Module["_sqlite3_column_decltype"] = wasmExports["sqlite3_column_decltype"];
        Module["_sqlite3_column_database_name"] = wasmExports["sqlite3_column_database_name"];
        Module["_sqlite3_column_table_name"] = wasmExports["sqlite3_column_table_name"];
        Module["_sqlite3_column_origin_name"] = wasmExports["sqlite3_column_origin_name"];
        Module["_sqlite3_bind_blob"] = wasmExports["sqlite3_bind_blob"];
        Module["_sqlite3_bind_double"] = wasmExports["sqlite3_bind_double"];
        Module["_sqlite3_bind_int"] = wasmExports["sqlite3_bind_int"];
        Module["_sqlite3_bind_int64"] = wasmExports["sqlite3_bind_int64"];
        Module["_sqlite3_bind_null"] = wasmExports["sqlite3_bind_null"];
        Module["_sqlite3_bind_pointer"] = wasmExports["sqlite3_bind_pointer"];
        Module["_sqlite3_bind_text"] = wasmExports["sqlite3_bind_text"];
        Module["_sqlite3_bind_parameter_count"] = wasmExports["sqlite3_bind_parameter_count"];
        Module["_sqlite3_bind_parameter_name"] = wasmExports["sqlite3_bind_parameter_name"];
        Module["_sqlite3_bind_parameter_index"] = wasmExports["sqlite3_bind_parameter_index"];
        Module["_sqlite3_db_handle"] = wasmExports["sqlite3_db_handle"];
        Module["_sqlite3_stmt_readonly"] = wasmExports["sqlite3_stmt_readonly"];
        Module["_sqlite3_stmt_isexplain"] = wasmExports["sqlite3_stmt_isexplain"];
        Module["_sqlite3_stmt_explain"] = wasmExports["sqlite3_stmt_explain"];
        Module["_sqlite3_stmt_busy"] = wasmExports["sqlite3_stmt_busy"];
        Module["_sqlite3_next_stmt"] = wasmExports["sqlite3_next_stmt"];
        Module["_sqlite3_stmt_status"] = wasmExports["sqlite3_stmt_status"];
        Module["_sqlite3_sql"] = wasmExports["sqlite3_sql"];
        Module["_sqlite3_expanded_sql"] = wasmExports["sqlite3_expanded_sql"];
        Module["_sqlite3_preupdate_old"] = wasmExports["sqlite3_preupdate_old"];
        Module["_sqlite3_preupdate_count"] = wasmExports["sqlite3_preupdate_count"];
        Module["_sqlite3_preupdate_depth"] = wasmExports["sqlite3_preupdate_depth"];
        Module["_sqlite3_preupdate_blobwrite"] = wasmExports["sqlite3_preupdate_blobwrite"];
        Module["_sqlite3_preupdate_new"] = wasmExports["sqlite3_preupdate_new"];
        Module["_sqlite3_value_numeric_type"] = wasmExports["sqlite3_value_numeric_type"];
        Module["_sqlite3_set_authorizer"] = wasmExports["sqlite3_set_authorizer"];
        Module["_sqlite3_strglob"] = wasmExports["sqlite3_strglob"];
        Module["_sqlite3_strlike"] = wasmExports["sqlite3_strlike"];
        Module["_sqlite3_auto_extension"] = wasmExports["sqlite3_auto_extension"];
        Module["_sqlite3_cancel_auto_extension"] = wasmExports["sqlite3_cancel_auto_extension"];
        Module["_sqlite3_reset_auto_extension"] = wasmExports["sqlite3_reset_auto_extension"];
        Module["_sqlite3_prepare_v3"] = wasmExports["sqlite3_prepare_v3"];
        Module["_sqlite3_create_module"] = wasmExports["sqlite3_create_module"];
        Module["_sqlite3_create_module_v2"] = wasmExports["sqlite3_create_module_v2"];
        Module["_sqlite3_drop_modules"] = wasmExports["sqlite3_drop_modules"];
        Module["_sqlite3_declare_vtab"] = wasmExports["sqlite3_declare_vtab"];
        Module["_sqlite3_vtab_on_conflict"] = wasmExports["sqlite3_vtab_on_conflict"];
        Module["_sqlite3_vtab_collation"] = wasmExports["sqlite3_vtab_collation"];
        Module["_sqlite3_vtab_in"] = wasmExports["sqlite3_vtab_in"];
        Module["_sqlite3_vtab_rhs_value"] = wasmExports["sqlite3_vtab_rhs_value"];
        Module["_sqlite3_vtab_distinct"] = wasmExports["sqlite3_vtab_distinct"];
        Module["_sqlite3_keyword_name"] = wasmExports["sqlite3_keyword_name"];
        Module["_sqlite3_keyword_count"] = wasmExports["sqlite3_keyword_count"];
        Module["_sqlite3_keyword_check"] = wasmExports["sqlite3_keyword_check"];
        Module["_sqlite3_complete"] = wasmExports["sqlite3_complete"];
        Module["_sqlite3_libversion"] = wasmExports["sqlite3_libversion"];
        Module["_sqlite3_libversion_number"] = wasmExports["sqlite3_libversion_number"];
        Module["_sqlite3_shutdown"] = wasmExports["sqlite3_shutdown"];
        Module["_sqlite3_last_insert_rowid"] = wasmExports["sqlite3_last_insert_rowid"];
        Module["_sqlite3_set_last_insert_rowid"] = wasmExports["sqlite3_set_last_insert_rowid"];
        Module["_sqlite3_changes64"] = wasmExports["sqlite3_changes64"];
        Module["_sqlite3_changes"] = wasmExports["sqlite3_changes"];
        Module["_sqlite3_total_changes64"] = wasmExports["sqlite3_total_changes64"];
        Module["_sqlite3_total_changes"] = wasmExports["sqlite3_total_changes"];
        Module["_sqlite3_txn_state"] = wasmExports["sqlite3_txn_state"];
        Module["_sqlite3_close_v2"] = wasmExports["sqlite3_close_v2"];
        Module["_sqlite3_busy_handler"] = wasmExports["sqlite3_busy_handler"];
        Module["_sqlite3_progress_handler"] = wasmExports["sqlite3_progress_handler"];
        Module["_sqlite3_busy_timeout"] = wasmExports["sqlite3_busy_timeout"];
        Module["_sqlite3_interrupt"] = wasmExports["sqlite3_interrupt"];
        Module["_sqlite3_is_interrupted"] = wasmExports["sqlite3_is_interrupted"];
        Module["_sqlite3_create_function"] = wasmExports["sqlite3_create_function"];
        Module["_sqlite3_create_function_v2"] = wasmExports["sqlite3_create_function_v2"];
        Module["_sqlite3_create_window_function"] = wasmExports["sqlite3_create_window_function"];
        Module["_sqlite3_overload_function"] = wasmExports["sqlite3_overload_function"];
        Module["_sqlite3_trace_v2"] = wasmExports["sqlite3_trace_v2"];
        Module["_sqlite3_commit_hook"] = wasmExports["sqlite3_commit_hook"];
        Module["_sqlite3_update_hook"] = wasmExports["sqlite3_update_hook"];
        Module["_sqlite3_rollback_hook"] = wasmExports["sqlite3_rollback_hook"];
        Module["_sqlite3_preupdate_hook"] = wasmExports["sqlite3_preupdate_hook"];
        Module["_sqlite3_set_errmsg"] = wasmExports["sqlite3_set_errmsg"];
        Module["_sqlite3_error_offset"] = wasmExports["sqlite3_error_offset"];
        Module["_sqlite3_errcode"] = wasmExports["sqlite3_errcode"];
        Module["_sqlite3_extended_errcode"] = wasmExports["sqlite3_extended_errcode"];
        Module["_sqlite3_errstr"] = wasmExports["sqlite3_errstr"];
        Module["_sqlite3_limit"] = wasmExports["sqlite3_limit"];
        Module["_sqlite3_open"] = wasmExports["sqlite3_open"];
        Module["_sqlite3_open_v2"] = wasmExports["sqlite3_open_v2"];
        Module["_sqlite3_create_collation"] = wasmExports["sqlite3_create_collation"];
        Module["_sqlite3_create_collation_v2"] = wasmExports["sqlite3_create_collation_v2"];
        Module["_sqlite3_collation_needed"] = wasmExports["sqlite3_collation_needed"];
        Module["_sqlite3_get_autocommit"] = wasmExports["sqlite3_get_autocommit"];
        Module["_sqlite3_table_column_metadata"] = wasmExports["sqlite3_table_column_metadata"];
        Module["_sqlite3_extended_result_codes"] = wasmExports["sqlite3_extended_result_codes"];
        Module["_sqlite3_uri_key"] = wasmExports["sqlite3_uri_key"];
        Module["_sqlite3_uri_int64"] = wasmExports["sqlite3_uri_int64"];
        Module["_sqlite3_db_name"] = wasmExports["sqlite3_db_name"];
        Module["_sqlite3_db_filename"] = wasmExports["sqlite3_db_filename"];
        Module["_sqlite3_db_readonly"] = wasmExports["sqlite3_db_readonly"];
        Module["_sqlite3_compileoption_used"] = wasmExports["sqlite3_compileoption_used"];
        Module["_sqlite3_compileoption_get"] = wasmExports["sqlite3_compileoption_get"];
        Module["_sqlite3session_diff"] = wasmExports["sqlite3session_diff"];
        Module["_sqlite3session_attach"] = wasmExports["sqlite3session_attach"];
        Module["_sqlite3session_create"] = wasmExports["sqlite3session_create"];
        Module["_sqlite3session_delete"] = wasmExports["sqlite3session_delete"];
        Module["_sqlite3session_table_filter"] = wasmExports["sqlite3session_table_filter"];
        Module["_sqlite3session_changeset"] = wasmExports["sqlite3session_changeset"];
        Module["_sqlite3session_changeset_strm"] = wasmExports["sqlite3session_changeset_strm"];
        Module["_sqlite3session_patchset_strm"] = wasmExports["sqlite3session_patchset_strm"];
        Module["_sqlite3session_patchset"] = wasmExports["sqlite3session_patchset"];
        Module["_sqlite3session_enable"] = wasmExports["sqlite3session_enable"];
        Module["_sqlite3session_indirect"] = wasmExports["sqlite3session_indirect"];
        Module["_sqlite3session_isempty"] = wasmExports["sqlite3session_isempty"];
        Module["_sqlite3session_memory_used"] = wasmExports["sqlite3session_memory_used"];
        Module["_sqlite3session_object_config"] = wasmExports["sqlite3session_object_config"];
        Module["_sqlite3session_changeset_size"] = wasmExports["sqlite3session_changeset_size"];
        Module["_sqlite3changeset_start"] = wasmExports["sqlite3changeset_start"];
        Module["_sqlite3changeset_start_v2"] = wasmExports["sqlite3changeset_start_v2"];
        Module["_sqlite3changeset_start_strm"] = wasmExports["sqlite3changeset_start_strm"];
        Module["_sqlite3changeset_start_v2_strm"] = wasmExports["sqlite3changeset_start_v2_strm"];
        Module["_sqlite3changeset_next"] = wasmExports["sqlite3changeset_next"];
        Module["_sqlite3changeset_op"] = wasmExports["sqlite3changeset_op"];
        Module["_sqlite3changeset_pk"] = wasmExports["sqlite3changeset_pk"];
        Module["_sqlite3changeset_old"] = wasmExports["sqlite3changeset_old"];
        Module["_sqlite3changeset_new"] = wasmExports["sqlite3changeset_new"];
        Module["_sqlite3changeset_conflict"] = wasmExports["sqlite3changeset_conflict"];
        Module["_sqlite3changeset_fk_conflicts"] = wasmExports["sqlite3changeset_fk_conflicts"];
        Module["_sqlite3changeset_finalize"] = wasmExports["sqlite3changeset_finalize"];
        Module["_sqlite3changeset_invert"] = wasmExports["sqlite3changeset_invert"];
        Module["_sqlite3changeset_invert_strm"] = wasmExports["sqlite3changeset_invert_strm"];
        Module["_sqlite3changeset_apply_v2"] = wasmExports["sqlite3changeset_apply_v2"];
        Module["_sqlite3changeset_apply_v3"] = wasmExports["sqlite3changeset_apply_v3"];
        Module["_sqlite3changeset_apply"] = wasmExports["sqlite3changeset_apply"];
        Module["_sqlite3changeset_apply_v3_strm"] = wasmExports["sqlite3changeset_apply_v3_strm"];
        Module["_sqlite3changeset_apply_v2_strm"] = wasmExports["sqlite3changeset_apply_v2_strm"];
        Module["_sqlite3changeset_apply_strm"] = wasmExports["sqlite3changeset_apply_strm"];
        Module["_sqlite3changegroup_new"] = wasmExports["sqlite3changegroup_new"];
        Module["_sqlite3changegroup_add"] = wasmExports["sqlite3changegroup_add"];
        Module["_sqlite3changegroup_output"] = wasmExports["sqlite3changegroup_output"];
        Module["_sqlite3changegroup_add_strm"] = wasmExports["sqlite3changegroup_add_strm"];
        Module["_sqlite3changegroup_output_strm"] = wasmExports["sqlite3changegroup_output_strm"];
        Module["_sqlite3changegroup_delete"] = wasmExports["sqlite3changegroup_delete"];
        Module["_sqlite3changeset_concat"] = wasmExports["sqlite3changeset_concat"];
        Module["_sqlite3changeset_concat_strm"] = wasmExports["sqlite3changeset_concat_strm"];
        Module["_sqlite3session_config"] = wasmExports["sqlite3session_config"];
        Module["_sqlite3_sourceid"] = wasmExports["sqlite3_sourceid"];
        Module["_sqlite3__wasm_pstack_ptr"] = wasmExports["sqlite3__wasm_pstack_ptr"];
        Module["_sqlite3__wasm_pstack_restore"] = wasmExports["sqlite3__wasm_pstack_restore"];
        Module["_sqlite3__wasm_pstack_alloc"] = wasmExports["sqlite3__wasm_pstack_alloc"];
        Module["_sqlite3__wasm_pstack_remaining"] = wasmExports["sqlite3__wasm_pstack_remaining"];
        Module["_sqlite3__wasm_pstack_quota"] = wasmExports["sqlite3__wasm_pstack_quota"];
        Module["_sqlite3__wasm_test_struct"] = wasmExports["sqlite3__wasm_test_struct"];
        Module["_sqlite3__wasm_enum_json"] = wasmExports["sqlite3__wasm_enum_json"];
        Module["_sqlite3__wasm_vfs_unlink"] = wasmExports["sqlite3__wasm_vfs_unlink"];
        Module["_sqlite3__wasm_db_vfs"] = wasmExports["sqlite3__wasm_db_vfs"];
        Module["_sqlite3__wasm_db_reset"] = wasmExports["sqlite3__wasm_db_reset"];
        Module["_sqlite3__wasm_db_export_chunked"] = wasmExports["sqlite3__wasm_db_export_chunked"];
        Module["_sqlite3__wasm_db_serialize"] = wasmExports["sqlite3__wasm_db_serialize"];
        Module["_sqlite3__wasm_vfs_create_file"] = wasmExports["sqlite3__wasm_vfs_create_file"];
        Module["_sqlite3__wasm_posix_create_file"] = wasmExports["sqlite3__wasm_posix_create_file"];
        Module["_sqlite3__wasm_kvvfsMakeKey"] = wasmExports["sqlite3__wasm_kvvfsMakeKey"];
        Module["_sqlite3__wasm_kvvfs_methods"] = wasmExports["sqlite3__wasm_kvvfs_methods"];
        Module["_sqlite3__wasm_vtab_config"] = wasmExports["sqlite3__wasm_vtab_config"];
        Module["_sqlite3__wasm_db_config_ip"] = wasmExports["sqlite3__wasm_db_config_ip"];
        Module["_sqlite3__wasm_db_config_pii"] = wasmExports["sqlite3__wasm_db_config_pii"];
        Module["_sqlite3__wasm_db_config_s"] = wasmExports["sqlite3__wasm_db_config_s"];
        Module["_sqlite3__wasm_config_i"] = wasmExports["sqlite3__wasm_config_i"];
        Module["_sqlite3__wasm_config_ii"] = wasmExports["sqlite3__wasm_config_ii"];
        Module["_sqlite3__wasm_config_j"] = wasmExports["sqlite3__wasm_config_j"];
        Module["_sqlite3__wasm_qfmt_token"] = wasmExports["sqlite3__wasm_qfmt_token"];
        Module["_sqlite3__wasm_kvvfs_decode"] = wasmExports["sqlite3__wasm_kvvfs_decode"];
        Module["_sqlite3__wasm_kvvfs_encode"] = wasmExports["sqlite3__wasm_kvvfs_encode"];
        Module["_sqlite3__wasm_init_wasmfs"] = wasmExports["sqlite3__wasm_init_wasmfs"];
        Module["_sqlite3__wasm_test_intptr"] = wasmExports["sqlite3__wasm_test_intptr"];
        Module["_sqlite3__wasm_test_voidptr"] = wasmExports["sqlite3__wasm_test_voidptr"];
        Module["_sqlite3__wasm_test_int64_max"] = wasmExports["sqlite3__wasm_test_int64_max"];
        Module["_sqlite3__wasm_test_int64_min"] = wasmExports["sqlite3__wasm_test_int64_min"];
        Module["_sqlite3__wasm_test_int64_times2"] = wasmExports["sqlite3__wasm_test_int64_times2"];
        Module["_sqlite3__wasm_test_int64_minmax"] = wasmExports["sqlite3__wasm_test_int64_minmax"];
        Module["_sqlite3__wasm_test_int64ptr"] = wasmExports["sqlite3__wasm_test_int64ptr"];
        Module["_sqlite3__wasm_test_stack_overflow"] = wasmExports["sqlite3__wasm_test_stack_overflow"];
        Module["_sqlite3__wasm_test_str_hello"] = wasmExports["sqlite3__wasm_test_str_hello"];
        Module["_sqlite3__wasm_SQLTester_strglob"] = wasmExports["sqlite3__wasm_SQLTester_strglob"];
        Module["_malloc"] = wasmExports["malloc"];
        Module["_free"] = wasmExports["free"];
        Module["_realloc"] = wasmExports["realloc"];
        _emscripten_builtin_memalign = wasmExports["emscripten_builtin_memalign"];
        wasmExports["_emscripten_stack_restore"];
        wasmExports["_emscripten_stack_alloc"];
        wasmExports["emscripten_stack_get_current"];
        wasmExports["__indirect_function_table"];
      }
      var wasmImports = {
        __syscall_chmod: ___syscall_chmod,
        __syscall_faccessat: ___syscall_faccessat,
        __syscall_fchmod: ___syscall_fchmod,
        __syscall_fchown32: ___syscall_fchown32,
        __syscall_fcntl64: ___syscall_fcntl64,
        __syscall_fstat64: ___syscall_fstat64,
        __syscall_ftruncate64: ___syscall_ftruncate64,
        __syscall_getcwd: ___syscall_getcwd,
        __syscall_ioctl: ___syscall_ioctl,
        __syscall_lstat64: ___syscall_lstat64,
        __syscall_mkdirat: ___syscall_mkdirat,
        __syscall_newfstatat: ___syscall_newfstatat,
        __syscall_openat: ___syscall_openat,
        __syscall_readlinkat: ___syscall_readlinkat,
        __syscall_rmdir: ___syscall_rmdir,
        __syscall_stat64: ___syscall_stat64,
        __syscall_unlinkat: ___syscall_unlinkat,
        __syscall_utimensat: ___syscall_utimensat,
        _localtime_js: __localtime_js,
        _mmap_js: __mmap_js,
        _munmap_js: __munmap_js,
        _tzset_js: __tzset_js,
        clock_time_get: _clock_time_get,
        emscripten_date_now: _emscripten_date_now,
        emscripten_get_heap_max: _emscripten_get_heap_max,
        emscripten_get_now: _emscripten_get_now,
        emscripten_resize_heap: _emscripten_resize_heap,
        environ_get: _environ_get,
        environ_sizes_get: _environ_sizes_get,
        fd_close: _fd_close,
        fd_fdstat_get: _fd_fdstat_get,
        fd_read: _fd_read,
        fd_seek: _fd_seek,
        fd_sync: _fd_sync,
        fd_write: _fd_write,
        memory: wasmMemory
      };
      function run() {
        if (runDependencies > 0) {
          dependenciesFulfilled = run;
          return;
        }
        preRun();
        if (runDependencies > 0) {
          dependenciesFulfilled = run;
          return;
        }
        function doRun() {
          Module["calledRun"] = true;
          if (ABORT) return;
          initRuntime();
          readyPromiseResolve?.(Module);
          Module["onRuntimeInitialized"]?.();
          postRun();
        }
        if (Module["setStatus"]) {
          Module["setStatus"]("Running...");
          setTimeout(() => {
            setTimeout(() => Module["setStatus"](""), 1);
            doRun();
          }, 1);
        } else doRun();
      }
      var wasmExports = await createWasm();
      run();
      Module.runSQLite3PostLoadInit = async function (sqlite3InitScriptInfo, EmscriptenModule, sqlite3IsUnderTest) {

        delete EmscriptenModule.runSQLite3PostLoadInit;
        globalThis.sqlite3ApiBootstrap = async function sqlite3ApiBootstrap(apiConfig = globalThis.sqlite3ApiConfig || sqlite3ApiBootstrap.defaultConfig) {
          if (sqlite3ApiBootstrap.sqlite3) {
            (sqlite3ApiBootstrap.sqlite3.config || console).warn("sqlite3ApiBootstrap() called multiple times.", "Config and external initializers are ignored on calls after the first.");
            return sqlite3ApiBootstrap.sqlite3;
          }
          const config = Object.assign(Object.create(null), {
            exports: void 0,
            memory: void 0,
            bigIntEnabled: !!globalThis.BigInt64Array,
            debug: console.debug.bind(console),
            warn: console.warn.bind(console),
            error: console.error.bind(console),
            log: console.log.bind(console),
            wasmfsOpfsDir: "/opfs",
            useStdAlloc: false
          }, apiConfig || {});
          Object.assign(config, {
            allocExportName: config.useStdAlloc ? "malloc" : "sqlite3_malloc",
            deallocExportName: config.useStdAlloc ? "free" : "sqlite3_free",
            reallocExportName: config.useStdAlloc ? "realloc" : "sqlite3_realloc"
          });
          ["exports", "memory", "functionTable", "wasmfsOpfsDir"].forEach(k => {
            if ("function" === typeof config[k]) config[k] = config[k]();
          });
          const capi = Object.create(null);
          const wasm = Object.create(null);
          const __rcStr = rc => {
            return capi.sqlite3_js_rc_str && capi.sqlite3_js_rc_str(rc) || "Unknown result code #" + rc;
          };
          const isInt32 = n => "number" === typeof n && n === (n | 0) && n <= 2147483647 && n >= -2147483648;
          class SQLite3Error extends Error {
            constructor(...args) {
              let rc;
              if (args.length) if (isInt32(args[0])) {
                rc = args[0];
                if (1 === args.length) super(__rcStr(args[0]));else {
                  const rcStr = __rcStr(rc);
                  if ("object" === typeof args[1]) super(rcStr, args[1]);else {
                    args[0] = rcStr + ":";
                    super(args.join(" "));
                  }
                }
              } else if (2 === args.length && "object" === typeof args[1]) super(...args);else super(args.join(" "));
              this.resultCode = rc || capi.SQLITE_ERROR;
              this.name = "SQLite3Error";
            }
          }
          SQLite3Error.toss = (...args) => {
            throw new SQLite3Error(...args);
          };
          const toss3 = SQLite3Error.toss;
          if (config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)) toss3("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.");
          const bigIntFits64 = function f(b) {
            if (!f._max) {
              f._max = BigInt("0x7fffffffffffffff");
              f._min = ~f._max;
            }
            return b >= f._min && b <= f._max;
          };
          const bigIntFits32 = b => b >= -2147483647n - 1n && b <= 2147483647n;
          const bigIntFitsDouble = function f(b) {
            if (!f._min) {
              f._min = Number.MIN_SAFE_INTEGER;
              f._max = Number.MAX_SAFE_INTEGER;
            }
            return b >= f._min && b <= f._max;
          };
          const isTypedArray = v => {
            return v && v.constructor && isInt32(v.constructor.BYTES_PER_ELEMENT) ? v : false;
          };
          const isBindableTypedArray = v => v && (v instanceof Uint8Array || v instanceof Int8Array || v instanceof ArrayBuffer);
          const isSQLableTypedArray = v => v && (v instanceof Uint8Array || v instanceof Int8Array || v instanceof ArrayBuffer);
          const affirmBindableTypedArray = v => isBindableTypedArray(v) || toss3("Value is not of a supported TypedArray type.");
          const flexibleString = function (v) {
            if (isSQLableTypedArray(v)) return wasm.typedArrayToString(v instanceof ArrayBuffer ? new Uint8Array(v) : v, 0, v.length);else if (Array.isArray(v)) return v.join("");else if (wasm.isPtr(v)) v = wasm.cstrToJs(v);
            return v;
          };
          class WasmAllocError extends Error {
            constructor(...args) {
              if (2 === args.length && "object" === typeof args[1]) super(...args);else if (args.length) super(args.join(" "));else super("Allocation failed.");
              this.resultCode = capi.SQLITE_NOMEM;
              this.name = "WasmAllocError";
            }
          }
          WasmAllocError.toss = (...args) => {
            throw new WasmAllocError(...args);
          };
          Object.assign(capi, {
            sqlite3_bind_blob: void 0,
            sqlite3_bind_text: void 0,
            sqlite3_create_function_v2: (pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal, xDestroy) => {},
            sqlite3_create_function: (pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal) => {},
            sqlite3_create_window_function: (pDb, funcName, nArg, eTextRep, pApp, xStep, xFinal, xValue, xInverse, xDestroy) => {},
            sqlite3_prepare_v3: (dbPtr, sql, sqlByteLen, prepFlags, stmtPtrPtr, strPtrPtr) => {},
            sqlite3_prepare_v2: (dbPtr, sql, sqlByteLen, stmtPtrPtr, strPtrPtr) => {},
            sqlite3_exec: (pDb, sql, callback, pVoid, pErrMsg) => {},
            sqlite3_randomness: (n, outPtr) => {}
          });
          const util = {
            affirmBindableTypedArray,
            flexibleString,
            bigIntFits32,
            bigIntFits64,
            bigIntFitsDouble,
            isBindableTypedArray,
            isInt32,
            isSQLableTypedArray,
            isTypedArray,
            isUIThread: () => globalThis.window === globalThis && !!globalThis.document,
            toss: function (...args) {
              throw new Error(args.join(" "));
            },
            toss3,
            typedArrayPart: wasm.typedArrayPart,
            assert: function (arg, msg) {
              if (!arg) util.toss("Assertion failed:", msg);
            },
            affirmDbHeader: function (bytes) {
              if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes);
              const header = "SQLite format 3";
              if (15 > bytes.byteLength) toss3("Input does not contain an SQLite3 database header.");
              for (let i = 0; i < 15; ++i) if (header.charCodeAt(i) !== bytes[i]) toss3("Input does not contain an SQLite3 database header.");
            },
            affirmIsDb: function (bytes) {
              if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes);
              const n = bytes.byteLength;
              if (n < 512 || n % 512 !== 0) toss3("Byte array size", n, "is invalid for an SQLite3 db.");
              util.affirmDbHeader(bytes);
            }
          };
          Object.assign(wasm, {
            exports: config.exports || toss3("Missing API config.exports (WASM module exports)."),
            memory: config.memory || config.exports["memory"] || toss3("API config object requires a WebAssembly.Memory object", "in either config.exports.memory (exported)", "or config.memory (imported)."),
            pointerSize: "number" === typeof config.exports.sqlite3_libversion() ? 4 : 8,
            bigIntEnabled: !!config.bigIntEnabled,
            functionTable: config.functionTable,
            alloc: void 0,
            realloc: void 0,
            dealloc: void 0
          });
          wasm.allocFromTypedArray = function (srcTypedArray) {
            if (srcTypedArray instanceof ArrayBuffer) srcTypedArray = new Uint8Array(srcTypedArray);
            affirmBindableTypedArray(srcTypedArray);
            const pRet = wasm.alloc(srcTypedArray.byteLength || 1);
            wasm.heapForSize(srcTypedArray.constructor).set(srcTypedArray.byteLength ? srcTypedArray : [0], Number(pRet));
            return pRet;
          };
          {
            const keyAlloc = config.allocExportName,
              keyDealloc = config.deallocExportName,
              keyRealloc = config.reallocExportName;
            for (const key of [keyAlloc, keyDealloc, keyRealloc]) if (!(wasm.exports[key] instanceof Function)) toss3("Missing required exports[", key, "] function.");
            wasm.alloc = function f(n) {
              return f.impl(n) || WasmAllocError.toss("Failed to allocate", n, " bytes.");
            };
            wasm.alloc.impl = wasm.exports[keyAlloc];
            wasm.realloc = function f(m, n) {
              const m2 = f.impl(wasm.ptr.coerce(m), n);
              return n ? m2 || WasmAllocError.toss("Failed to reallocate", n, " bytes.") : wasm.ptr.null;
            };
            wasm.realloc.impl = wasm.exports[keyRealloc];
            wasm.dealloc = function f(m) {
              f.impl(wasm.ptr.coerce(m));
            };
            wasm.dealloc.impl = wasm.exports[keyDealloc];
          }
          wasm.compileOptionUsed = function f(optName) {
            if (!arguments.length) {
              if (f._result) return f._result;else if (!f._opt) {
                f._rx = /^([^=]+)=(.+)/;
                f._rxInt = /^-?\d+$/;
                f._opt = function (opt, rv) {
                  const m = f._rx.exec(opt);
                  rv[0] = m ? m[1] : opt;
                  rv[1] = m ? f._rxInt.test(m[2]) ? +m[2] : m[2] : true;
                };
              }
              const rc = Object.create(null),
                ov = [0, 0];
              let i = 0,
                k;
              while (k = capi.sqlite3_compileoption_get(i++)) {
                f._opt(k, ov);
                rc[ov[0]] = ov[1];
              }
              return f._result = rc;
            } else if (Array.isArray(optName)) {
              const rc = Object.create(null);
              optName.forEach(v => {
                rc[v] = capi.sqlite3_compileoption_used(v);
              });
              return rc;
            } else if ("object" === typeof optName) {
              Object.keys(optName).forEach(k => {
                optName[k] = capi.sqlite3_compileoption_used(k);
              });
              return optName;
            }
            return "string" === typeof optName ? !!capi.sqlite3_compileoption_used(optName) : false;
          };
          wasm.pstack = Object.assign(Object.create(null), {
            restore: wasm.exports.sqlite3__wasm_pstack_restore,
            alloc: function (n) {
              if ("string" === typeof n && !(n = wasm.sizeofIR(n))) WasmAllocError.toss("Invalid value for pstack.alloc(", arguments[0], ")");
              return wasm.exports.sqlite3__wasm_pstack_alloc(n) || WasmAllocError.toss("Could not allocate", n, "bytes from the pstack.");
            },
            allocChunks: function (n, sz) {
              if ("string" === typeof sz && !(sz = wasm.sizeofIR(sz))) WasmAllocError.toss("Invalid size value for allocChunks(", arguments[1], ")");
              const mem = wasm.pstack.alloc(n * sz);
              const rc = [mem];
              let i = 1,
                offset = sz;
              for (; i < n; ++i, offset += sz) rc.push(wasm.ptr.add(mem, offset));
              return rc;
            },
            allocPtr: (n = 1, safePtrSize = true) => {
              return 1 === n ? wasm.pstack.alloc(safePtrSize ? 8 : wasm.ptr.size) : wasm.pstack.allocChunks(n, safePtrSize ? 8 : wasm.ptr.size);
            },
            call: function (f) {
              const stackPos = wasm.pstack.pointer;
              try {
                return f(sqlite3);
              } finally {
                wasm.pstack.restore(stackPos);
              }
            }
          });
          Object.defineProperties(wasm.pstack, {
            pointer: {
              configurable: false,
              iterable: true,
              writeable: false,
              get: wasm.exports.sqlite3__wasm_pstack_ptr
            },
            quota: {
              configurable: false,
              iterable: true,
              writeable: false,
              get: wasm.exports.sqlite3__wasm_pstack_quota
            },
            remaining: {
              configurable: false,
              iterable: true,
              writeable: false,
              get: wasm.exports.sqlite3__wasm_pstack_remaining
            }
          });
          capi.sqlite3_randomness = (...args) => {
            if (1 === args.length && util.isTypedArray(args[0]) && 1 === args[0].BYTES_PER_ELEMENT) {
              const ta = args[0];
              if (0 === ta.byteLength) {
                wasm.exports.sqlite3_randomness(0, wasm.ptr.null);
                return ta;
              }
              const stack = wasm.pstack.pointer;
              try {
                let n = ta.byteLength,
                  offset = 0;
                const r = wasm.exports.sqlite3_randomness;
                const heap = wasm.heap8u();
                const nAlloc = n < 512 ? n : 512;
                const ptr = wasm.pstack.alloc(nAlloc);
                do {
                  const j = n > nAlloc ? nAlloc : n;
                  r(j, ptr);
                  ta.set(wasm.typedArrayPart(heap, ptr, wasm.ptr.add(ptr, j)), offset);
                  n -= j;
                  offset += j;
                } while (n > 0);
              } catch (e) {
                config.error("Highly unexpected (and ignored!) exception in sqlite3_randomness():", e);
              } finally {
                wasm.pstack.restore(stack);
              }
              return ta;
            }
            wasm.exports.sqlite3_randomness(...args);
          };
          capi.sqlite3_wasmfs_opfs_dir = function () {
            if (void 0 !== this.dir) return this.dir;
            const pdir = config.wasmfsOpfsDir;
            if (!pdir || !globalThis.FileSystemHandle || !globalThis.FileSystemDirectoryHandle || !globalThis.FileSystemFileHandle || !wasm.exports.sqlite3__wasm_init_wasmfs) return this.dir = "";
            try {
              if (pdir && 0 === wasm.xCallWrapped("sqlite3__wasm_init_wasmfs", "i32", ["string"], pdir)) return this.dir = pdir;else return this.dir = "";
            } catch (e) {
              return this.dir = "";
            }
          }.bind(Object.create(null));
          capi.sqlite3_wasmfs_filename_is_persistent = function (name) {
            const p = capi.sqlite3_wasmfs_opfs_dir();
            return p && name ? name.startsWith(p + "/") : false;
          };
          capi.sqlite3_js_db_uses_vfs = function (pDb, vfsName, dbName = 0) {
            try {
              const pK = capi.sqlite3_vfs_find(vfsName);
              if (!pK) return false;else if (!pDb) return pK === capi.sqlite3_vfs_find(0) ? pK : false;else return pK === capi.sqlite3_js_db_vfs(pDb, dbName) ? pK : false;
            } catch (e) {
              return false;
            }
          };
          capi.sqlite3_js_vfs_list = function () {
            const rc = [];
            let pVfs = capi.sqlite3_vfs_find(wasm.ptr.null);
            while (pVfs) {
              const oVfs = new capi.sqlite3_vfs(pVfs);
              rc.push(wasm.cstrToJs(oVfs.$zName));
              pVfs = oVfs.$pNext;
              oVfs.dispose();
            }
            return rc;
          };
          capi.sqlite3_js_db_export = function (pDb, schema = 0) {
            pDb = wasm.xWrap.testConvertArg("sqlite3*", pDb);
            if (!pDb) toss3("Invalid sqlite3* argument.");
            if (!wasm.bigIntEnabled) toss3("BigInt support is not enabled.");
            const scope = wasm.scopedAllocPush();
            let pOut;
            try {
              const pSize = wasm.scopedAlloc(8 + wasm.ptr.size);
              const ppOut = wasm.ptr.add(pSize, 8);
              const zSchema = schema ? wasm.isPtr(schema) ? schema : wasm.scopedAllocCString("" + schema) : wasm.ptr.null;
              let rc = wasm.exports.sqlite3__wasm_db_serialize(pDb, zSchema, ppOut, pSize, 0);
              if (rc) toss3("Database serialization failed with code", sqlite3.capi.sqlite3_js_rc_str(rc));
              pOut = wasm.peekPtr(ppOut);
              const nOut = wasm.peek(pSize, "i64");
              rc = nOut ? wasm.heap8u().slice(Number(pOut), Number(pOut) + Number(nOut)) : new Uint8Array();
              return rc;
            } finally {
              if (pOut) wasm.exports.sqlite3_free(pOut);
              wasm.scopedAllocPop(scope);
            }
          };
          capi.sqlite3_js_db_vfs = (dbPointer, dbName = wasm.ptr.null) => util.sqlite3__wasm_db_vfs(dbPointer, dbName);
          capi.sqlite3_js_aggregate_context = (pCtx, n) => {
            return capi.sqlite3_aggregate_context(pCtx, n) || (n ? WasmAllocError.toss("Cannot allocate", n, "bytes for sqlite3_aggregate_context()") : 0);
          };
          capi.sqlite3_js_posix_create_file = function (filename, data, dataLen) {
            let pData;
            if (data && wasm.isPtr(data)) pData = data;else if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
              pData = wasm.allocFromTypedArray(data);
              if (arguments.length < 3 || !util.isInt32(dataLen) || dataLen < 0) dataLen = data.byteLength;
            } else SQLite3Error.toss("Invalid 2nd argument for sqlite3_js_posix_create_file().");
            try {
              if (!util.isInt32(dataLen) || dataLen < 0) SQLite3Error.toss("Invalid 3rd argument for sqlite3_js_posix_create_file().");
              const rc = util.sqlite3__wasm_posix_create_file(filename, pData, dataLen);
              if (rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code", capi.sqlite3_js_rc_str(rc));
            } finally {
              if (pData && pData !== data) wasm.dealloc(pData);
            }
          };
          capi.sqlite3_js_vfs_create_file = function (vfs, filename, data, dataLen) {
            config.warn("sqlite3_js_vfs_create_file() is deprecated and", "should be avoided because it can lead to C-level crashes.", "See its documentation for alternatives.");
            let pData;
            if (data) {
              if (wasm.isPtr(data)) pData = data;else {
                if (data instanceof ArrayBuffer) data = new Uint8Array(data);
                if (data instanceof Uint8Array) {
                  pData = wasm.allocFromTypedArray(data);
                  if (arguments.length < 4 || !util.isInt32(dataLen) || dataLen < 0) dataLen = data.byteLength;
                } else SQLite3Error.toss("Invalid 3rd argument type for sqlite3_js_vfs_create_file().");
              }
            } else pData = 0;
            if (!util.isInt32(dataLen) || dataLen < 0) {
              if (pData && pData !== data) wasm.dealloc(pData);
              SQLite3Error.toss("Invalid 4th argument for sqlite3_js_vfs_create_file().");
            }
            try {
              const rc = util.sqlite3__wasm_vfs_create_file(vfs, filename, pData, dataLen);
              if (rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code", capi.sqlite3_js_rc_str(rc));
            } finally {
              if (pData && pData !== data) wasm.dealloc(pData);
            }
          };
          capi.sqlite3_js_sql_to_string = sql => {
            if ("string" === typeof sql) return sql;
            const x = flexibleString(v);
            return x === v ? void 0 : x;
          };
          capi.sqlite3_db_config = function (pDb, op, ...args) {
            switch (op) {
              case capi.SQLITE_DBCONFIG_ENABLE_FKEY:
              case capi.SQLITE_DBCONFIG_ENABLE_TRIGGER:
              case capi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER:
              case capi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION:
              case capi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE:
              case capi.SQLITE_DBCONFIG_ENABLE_QPSG:
              case capi.SQLITE_DBCONFIG_TRIGGER_EQP:
              case capi.SQLITE_DBCONFIG_RESET_DATABASE:
              case capi.SQLITE_DBCONFIG_DEFENSIVE:
              case capi.SQLITE_DBCONFIG_WRITABLE_SCHEMA:
              case capi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE:
              case capi.SQLITE_DBCONFIG_DQS_DML:
              case capi.SQLITE_DBCONFIG_DQS_DDL:
              case capi.SQLITE_DBCONFIG_ENABLE_VIEW:
              case capi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT:
              case capi.SQLITE_DBCONFIG_TRUSTED_SCHEMA:
              case capi.SQLITE_DBCONFIG_STMT_SCANSTATUS:
              case capi.SQLITE_DBCONFIG_REVERSE_SCANORDER:
              case capi.SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE:
              case capi.SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE:
              case capi.SQLITE_DBCONFIG_ENABLE_COMMENTS:
                if (!this.ip) this.ip = wasm.xWrap("sqlite3__wasm_db_config_ip", "int", ["sqlite3*", "int", "int", "*"]);
                return this.ip(pDb, op, args[0], args[1] || 0);
              case capi.SQLITE_DBCONFIG_LOOKASIDE:
                if (!this.pii) this.pii = wasm.xWrap("sqlite3__wasm_db_config_pii", "int", ["sqlite3*", "int", "*", "int", "int"]);
                return this.pii(pDb, op, args[0], args[1], args[2]);
              case capi.SQLITE_DBCONFIG_MAINDBNAME:
                if (!this.s) this.s = wasm.xWrap("sqlite3__wasm_db_config_s", "int", ["sqlite3*", "int", "string:static"]);
                return this.s(pDb, op, args[0]);
              default:
                return capi.SQLITE_MISUSE;
            }
          }.bind(Object.create(null));
          capi.sqlite3_value_to_js = function (pVal, throwIfCannotConvert = true) {
            let arg;
            const valType = capi.sqlite3_value_type(pVal);
            switch (valType) {
              case capi.SQLITE_INTEGER:
                if (wasm.bigIntEnabled) {
                  arg = capi.sqlite3_value_int64(pVal);
                  if (util.bigIntFitsDouble(arg)) arg = Number(arg);
                } else arg = capi.sqlite3_value_double(pVal);
                break;
              case capi.SQLITE_FLOAT:
                arg = capi.sqlite3_value_double(pVal);
                break;
              case capi.SQLITE_TEXT:
                arg = capi.sqlite3_value_text(pVal);
                break;
              case capi.SQLITE_BLOB:
                {
                  const n = capi.sqlite3_value_bytes(pVal);
                  const pBlob = capi.sqlite3_value_blob(pVal);
                  if (n && !pBlob) sqlite3.WasmAllocError.toss("Cannot allocate memory for blob argument of", n, "byte(s)");
                  arg = n ? wasm.heap8u().slice(Number(pBlob), Number(pBlob) + Number(n)) : null;
                  break;
                }
              case capi.SQLITE_NULL:
                arg = null;
                break;
              default:
                if (throwIfCannotConvert) toss3(capi.SQLITE_MISMATCH, "Unhandled sqlite3_value_type():", valType);
                arg = void 0;
            }
            return arg;
          };
          capi.sqlite3_values_to_js = function (argc, pArgv, throwIfCannotConvert = true) {
            let i;
            const tgt = [];
            for (i = 0; i < argc; ++i) tgt.push(capi.sqlite3_value_to_js(wasm.peekPtr(wasm.ptr.add(pArgv, wasm.ptr.size * i)), throwIfCannotConvert));
            return tgt;
          };
          capi.sqlite3_result_error_js = function (pCtx, e) {
            if (e instanceof WasmAllocError) capi.sqlite3_result_error_nomem(pCtx);else capi.sqlite3_result_error(pCtx, "" + e, -1);
          };
          capi.sqlite3_result_js = function (pCtx, val) {
            if (val instanceof Error) {
              capi.sqlite3_result_error_js(pCtx, val);
              return;
            }
            try {
              switch (typeof val) {
                case "undefined":
                  break;
                case "boolean":
                  capi.sqlite3_result_int(pCtx, val ? 1 : 0);
                  break;
                case "bigint":
                  if (util.bigIntFits32(val)) capi.sqlite3_result_int(pCtx, Number(val));else if (util.bigIntFitsDouble(val)) capi.sqlite3_result_double(pCtx, Number(val));else if (wasm.bigIntEnabled) {
                    if (util.bigIntFits64(val)) capi.sqlite3_result_int64(pCtx, val);else toss3("BigInt value", val.toString(), "is too BigInt for int64.");
                  } else toss3("BigInt value", val.toString(), "is too BigInt.");
                  break;
                case "number":
                  {
                    let f;
                    if (util.isInt32(val)) f = capi.sqlite3_result_int;else if (wasm.bigIntEnabled && Number.isInteger(val) && util.bigIntFits64(BigInt(val))) f = capi.sqlite3_result_int64;else f = capi.sqlite3_result_double;
                    f(pCtx, val);
                    break;
                  }
                case "string":
                  {
                    const [p, n] = wasm.allocCString(val, true);
                    capi.sqlite3_result_text(pCtx, p, n, capi.SQLITE_WASM_DEALLOC);
                    break;
                  }
                case "object":
                  if (null === val) {
                    capi.sqlite3_result_null(pCtx);
                    break;
                  } else if (util.isBindableTypedArray(val)) {
                    const pBlob = wasm.allocFromTypedArray(val);
                    capi.sqlite3_result_blob(pCtx, pBlob, val.byteLength, capi.SQLITE_WASM_DEALLOC);
                    break;
                  }
                default:
                  toss3("Don't not how to handle this UDF result value:", typeof val, val);
              }
            } catch (e) {
              capi.sqlite3_result_error_js(pCtx, e);
            }
          };
          capi.sqlite3_column_js = function (pStmt, iCol, throwIfCannotConvert = true) {
            const v = capi.sqlite3_column_value(pStmt, iCol);
            return 0 === v ? void 0 : capi.sqlite3_value_to_js(v, throwIfCannotConvert);
          };
          {
            const __newOldValue = function (pObj, iCol, impl) {
              impl = capi[impl];
              if (!this.ptr) this.ptr = wasm.allocPtr();else wasm.pokePtr(this.ptr, 0);
              const rc = impl(pObj, iCol, this.ptr);
              if (rc) return SQLite3Error.toss(rc, arguments[2] + "() failed with code " + rc);
              const pv = wasm.peekPtr(this.ptr);
              return pv ? capi.sqlite3_value_to_js(pv, true) : void 0;
            }.bind(Object.create(null));
            capi.sqlite3_preupdate_new_js = (pDb, iCol) => __newOldValue(pDb, iCol, "sqlite3_preupdate_new");
            capi.sqlite3_preupdate_old_js = (pDb, iCol) => __newOldValue(pDb, iCol, "sqlite3_preupdate_old");
            capi.sqlite3changeset_new_js = (pChangesetIter, iCol) => __newOldValue(pChangesetIter, iCol, "sqlite3changeset_new");
            capi.sqlite3changeset_old_js = (pChangesetIter, iCol) => __newOldValue(pChangesetIter, iCol, "sqlite3changeset_old");
          }
          const sqlite3 = {
            WasmAllocError,
            SQLite3Error,
            capi,
            util,
            wasm,
            config,
            version: Object.create(null),
            client: void 0,
            asyncPostInit: async function ff() {
              if (ff.isReady instanceof Promise) return ff.isReady;
              let lia = this.initializersAsync;
              delete this.initializersAsync;
              const postInit = async () => {
                if (!sqlite3.__isUnderTest) {
                  delete sqlite3.util;
                  delete sqlite3.StructBinder;
                }
                return sqlite3;
              };
              const catcher = e => {
                config.error("an async sqlite3 initializer failed:", e);
                throw e;
              };
              if (!lia || !lia.length) return ff.isReady = postInit().catch(catcher);
              lia = lia.map(f => {
                return f instanceof Function ? async x => f(sqlite3) : f;
              });
              lia.push(postInit);
              let p = Promise.resolve(sqlite3);
              while (lia.length) p = p.then(lia.shift());
              return ff.isReady = p.catch(catcher);
            }.bind(sqlite3ApiBootstrap),
            scriptInfo: void 0
          };
          if ("undefined" !== typeof sqlite3IsUnderTest) sqlite3.__isUnderTest = !!sqlite3IsUnderTest;
          try {
            sqlite3ApiBootstrap.initializers.forEach(f => {
              f(sqlite3);
            });
          } catch (e) {
            console.error("sqlite3 bootstrap initializer threw:", e);
            throw e;
          }
          delete sqlite3ApiBootstrap.initializers;
          sqlite3ApiBootstrap.sqlite3 = sqlite3;
          if ("undefined" !== typeof sqlite3InitScriptInfo) {
            sqlite3InitScriptInfo.debugModule("sqlite3ApiBootstrap() complete", sqlite3);
            sqlite3.scriptInfo = sqlite3InitScriptInfo;
          }
          if (sqlite3.__isUnderTest) {
            if ("undefined" !== typeof EmscriptenModule) sqlite3.config.emscripten = EmscriptenModule;
            const iw = sqlite3.scriptInfo?.instantiateWasm;
            if (iw) {
              sqlite3.wasm.module = iw.module;
              sqlite3.wasm.instance = iw.instance;
              sqlite3.wasm.imports = iw.imports;
            }
          }
          delete globalThis.sqlite3ApiConfig;
          delete globalThis.sqlite3ApiBootstrap;
          delete sqlite3ApiBootstrap.defaultConfig;
          return sqlite3.asyncPostInit().then(s => {
            if ("undefined" !== typeof sqlite3InitScriptInfo) sqlite3InitScriptInfo.debugModule("sqlite3.asyncPostInit() complete", s);
            delete s.asyncPostInit;
            delete s.scriptInfo;
            delete s.emscripten;
            return s;
          });
        };
        globalThis.sqlite3ApiBootstrap.initializers = [];
        globalThis.sqlite3ApiBootstrap.initializersAsync = [];
        globalThis.sqlite3ApiBootstrap.defaultConfig = Object.create(null);
        globalThis.sqlite3ApiBootstrap.sqlite3 = void 0;
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {
          sqlite3.version = {
            "libVersion": "3.52.0",
            "libVersionNumber": 3052e3,
            "sourceId": "2026-01-30 06:37:34 407724c4e80efdf93d885e95b5209a100a3f470fe0298138be57201f65f9817e",
            "downloadVersion": 352e4,
            "scm": {
              "sha3-256": "407724c4e80efdf93d885e95b5209a100a3f470fe0298138be57201f65f9817e",
              "branch": "trunk",
              "tags": "",
              "datetime": "2026-01-30T06:37:34.096Z"
            }
          };
        });
        globalThis.WhWasmUtilInstaller = function WhWasmUtilInstaller(target) {

          if (void 0 === target.bigIntEnabled) target.bigIntEnabled = !!globalThis["BigInt64Array"];
          const toss = (...args) => {
            throw new Error(args.join(" "));
          };
          if (!target.pointerSize && !target.pointerIR && target.alloc && target.dealloc) {
            const ptr = target.alloc(1);
            target.pointerSize = "bigint" === typeof ptr ? 8 : 4;
            target.dealloc(ptr);
          }
          if (target.pointerSize && !target.pointerIR) target.pointerIR = 4 === target.pointerSize ? "i32" : "i64";
          const __ptrIR = target.pointerIR ??= "i32";
          const __ptrSize = target.pointerSize ??= "i32" === __ptrIR ? 4 : "i64" === __ptrIR ? 8 : 0;
          delete target.pointerSize;
          delete target.pointerIR;
          if ("i32" !== __ptrIR && "i64" !== __ptrIR) toss("Invalid pointerIR:", __ptrIR);else if (8 !== __ptrSize && 4 !== __ptrSize) toss("Invalid pointerSize:", __ptrSize);
          const __BigInt = target.bigIntEnabled ? v => BigInt(v || 0) : v => toss("BigInt support is disabled in this build.");
          const __Number = v => Number(v || 0);
          const __asPtrType = 4 === __ptrSize ? __Number : __BigInt;
          const __NullPtr = __asPtrType(0);
          const __ptrAdd = function (...args) {
            let rc = __asPtrType(0);
            for (const v of args) rc += __asPtrType(v);
            return rc;
          };
          {
            const __ptr = Object.create(null);
            Object.defineProperty(target, "ptr", {
              enumerable: true,
              get: () => __ptr,
              set: () => toss("The ptr property is read-only.")
            });
            (function f(name, val) {
              Object.defineProperty(__ptr, name, {
                enumerable: true,
                get: () => val,
                set: () => toss("ptr[" + name + "] is read-only.")
              });
              return f;
            })("null", __NullPtr)("size", __ptrSize)("ir", __ptrIR)("coerce", __asPtrType)("add", __ptrAdd)("addn", 4 === __ptrIR ? __ptrAdd : (...args) => Number(__ptrAdd(...args)));
          }
          if (!target.exports) Object.defineProperty(target, "exports", {
            enumerable: true,
            configurable: true,
            get: () => target.instance?.exports
          });
          const cache = Object.create(null);
          cache.heapSize = 0;
          cache.memory = null;
          cache.freeFuncIndexes = [];
          cache.scopedAlloc = [];
          cache.scopedAlloc.pushPtr = ptr => {
            cache.scopedAlloc[cache.scopedAlloc.length - 1].push(ptr);
            return ptr;
          };
          cache.utf8Decoder = new TextDecoder();
          cache.utf8Encoder = new TextEncoder("utf-8");
          target.sizeofIR = n => {
            switch (n) {
              case "i8":
                return 1;
              case "i16":
                return 2;
              case "i32":
              case "f32":
              case "float":
                return 4;
              case "i64":
              case "f64":
              case "double":
                return 8;
              case "*":
                return __ptrSize;
              default:
                return ("" + n).endsWith("*") ? __ptrSize : void 0;
            }
          };
          const heapWrappers = function () {
            if (!cache.memory) cache.memory = target.memory instanceof WebAssembly.Memory ? target.memory : target.exports.memory;else if (cache.heapSize === cache.memory.buffer.byteLength) return cache;
            const b = cache.memory.buffer;
            cache.HEAP8 = new Int8Array(b);
            cache.HEAP8U = new Uint8Array(b);
            cache.HEAP16 = new Int16Array(b);
            cache.HEAP16U = new Uint16Array(b);
            cache.HEAP32 = new Int32Array(b);
            cache.HEAP32U = new Uint32Array(b);
            cache.HEAP32F = new Float32Array(b);
            cache.HEAP64F = new Float64Array(b);
            if (target.bigIntEnabled) if ("undefined" !== typeof BigInt64Array) {
              cache.HEAP64 = new BigInt64Array(b);
              cache.HEAP64U = new BigUint64Array(b);
            } else toss("BigInt support is enabled, but the BigInt64Array type is missing.");
            cache.heapSize = b.byteLength;
            return cache;
          };
          target.heap8 = () => heapWrappers().HEAP8;
          target.heap8u = () => heapWrappers().HEAP8U;
          target.heap16 = () => heapWrappers().HEAP16;
          target.heap16u = () => heapWrappers().HEAP16U;
          target.heap32 = () => heapWrappers().HEAP32;
          target.heap32u = () => heapWrappers().HEAP32U;
          target.heapForSize = function (n, unsigned = true) {
            const c = cache.memory && cache.heapSize === cache.memory.buffer.byteLength ? cache : heapWrappers();
            switch (n) {
              case Int8Array:
                return c.HEAP8;
              case Uint8Array:
                return c.HEAP8U;
              case Int16Array:
                return c.HEAP16;
              case Uint16Array:
                return c.HEAP16U;
              case Int32Array:
                return c.HEAP32;
              case Uint32Array:
                return c.HEAP32U;
              case 8:
                return unsigned ? c.HEAP8U : c.HEAP8;
              case 16:
                return unsigned ? c.HEAP16U : c.HEAP16;
              case 32:
                return unsigned ? c.HEAP32U : c.HEAP32;
              case 64:
                if (c.HEAP64) return unsigned ? c.HEAP64U : c.HEAP64;
                break;
              default:
                if (target.bigIntEnabled) {
                  if (n === globalThis["BigUint64Array"]) return c.HEAP64U;else if (n === globalThis["BigInt64Array"]) return c.HEAP64;
                  break;
                }
            }
            toss("Invalid heapForSize() size: expecting 8, 16, 32,", "or (if BigInt is enabled) 64.");
          };
          const __funcTable = target.functionTable;
          delete target.functionTable;
          target.functionTable = __funcTable ? () => __funcTable : () => target.exports.__indirect_function_table;
          target.functionEntry = function (fptr) {
            const ft = target.functionTable();
            return fptr < ft.length ? ft.get(__asPtrType(fptr)) : void 0;
          };
          target.jsFuncToWasm = function f(func, sig) {
            if (!f._) f._ = {
              sigTypes: Object.assign(Object.create(null), {
                i: "i32",
                p: __ptrIR,
                P: __ptrIR,
                s: __ptrIR,
                j: "i64",
                f: "f32",
                d: "f64"
              }),
              typeCodes: Object.assign(Object.create(null), {
                f64: 124,
                f32: 125,
                i64: 126,
                i32: 127
              }),
              uleb128Encode: (tgt, method, n) => {
                if (n < 128) tgt[method](n);else tgt[method](n % 128 | 128, n >> 7);
              },
              rxJSig: /^(\w)\((\w*)\)$/,
              sigParams: sig => {
                const m = f._.rxJSig.exec(sig);
                return m ? m[2] : sig.substr(1);
              },
              letterType: x => f._.sigTypes[x] || toss("Invalid signature letter:", x),
              pushSigType: (dest, letter) => dest.push(f._.typeCodes[f._.letterType(letter)])
            };
            if ("string" === typeof func) {
              const x = sig;
              sig = func;
              func = x;
            }
            const _ = f._;
            const sigParams = _.sigParams(sig);
            const wasmCode = [1, 96];
            _.uleb128Encode(wasmCode, "push", sigParams.length);
            for (const x of sigParams) _.pushSigType(wasmCode, x);
            if ("v" === sig[0]) wasmCode.push(0);else {
              wasmCode.push(1);
              _.pushSigType(wasmCode, sig[0]);
            }
            _.uleb128Encode(wasmCode, "unshift", wasmCode.length);
            wasmCode.unshift(0, 97, 115, 109, 1, 0, 0, 0, 1);
            wasmCode.push(2, 7, 1, 1, 101, 1, 102, 0, 0, 7, 5, 1, 1, 102, 0, 0);
            return new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array(wasmCode)), {
              e: {
                f: func
              }
            }).exports["f"];
          };
          const __installFunction = function f(func, sig, scoped) {
            if (scoped && !cache.scopedAlloc.length) toss("No scopedAllocPush() scope is active.");
            if ("string" === typeof func) {
              const x = sig;
              sig = func;
              func = x;
            }
            if ("string" !== typeof sig || !(func instanceof Function)) toss("Invalid arguments: expecting (function,signature) or (signature,function).");
            const ft = target.functionTable();
            const oldLen = __asPtrType(ft.length);
            let ptr;
            while (ptr = cache.freeFuncIndexes.pop()) if (ft.get(ptr)) {
              ptr = null;
              continue;
            } else break;
            if (!ptr) {
              ptr = __asPtrType(oldLen);
              ft.grow(__asPtrType(1));
            }
            try {
              ft.set(ptr, func);
              if (scoped) cache.scopedAlloc.pushPtr(ptr);
              return ptr;
            } catch (e) {
              if (!(e instanceof TypeError)) {
                if (ptr === oldLen) cache.freeFuncIndexes.push(oldLen);
                throw e;
              }
            }
            try {
              const fptr = target.jsFuncToWasm(func, sig);
              ft.set(ptr, fptr);
              if (scoped) cache.scopedAlloc.pushPtr(ptr);
            } catch (e) {
              if (ptr === oldLen) cache.freeFuncIndexes.push(oldLen);
              throw e;
            }
            return ptr;
          };
          target.installFunction = (func, sig) => __installFunction(func, sig, false);
          target.scopedInstallFunction = (func, sig) => __installFunction(func, sig, true);
          target.uninstallFunction = function (ptr) {
            if (!ptr && __NullPtr !== ptr) return void 0;
            const ft = target.functionTable();
            cache.freeFuncIndexes.push(ptr);
            const rc = ft.get(ptr);
            ft.set(ptr, null);
            return rc;
          };
          target.peek = function f(ptr, type = "i8") {
            if (type.endsWith("*")) type = __ptrIR;
            const c = cache.memory && cache.heapSize === cache.memory.buffer.byteLength ? cache : heapWrappers();
            const list = Array.isArray(ptr) ? [] : void 0;
            let rc;
            do {
              if (list) ptr = arguments[0].shift();
              switch (type) {
                case "i1":
                case "i8":
                  rc = c.HEAP8[Number(ptr) >> 0];
                  break;
                case "i16":
                  rc = c.HEAP16[Number(ptr) >> 1];
                  break;
                case "i32":
                  rc = c.HEAP32[Number(ptr) >> 2];
                  break;
                case "float":
                case "f32":
                  rc = c.HEAP32F[Number(ptr) >> 2];
                  break;
                case "double":
                case "f64":
                  rc = Number(c.HEAP64F[Number(ptr) >> 3]);
                  break;
                case "i64":
                  if (c.HEAP64) {
                    rc = __BigInt(c.HEAP64[Number(ptr) >> 3]);
                    break;
                  }
                default:
                  toss("Invalid type for peek():", type);
              }
              if (list) list.push(rc);
            } while (list && arguments[0].length);
            return list || rc;
          };
          target.poke = function (ptr, value, type = "i8") {
            if (type.endsWith("*")) type = __ptrIR;
            const c = cache.memory && cache.heapSize === cache.memory.buffer.byteLength ? cache : heapWrappers();
            for (const p of Array.isArray(ptr) ? ptr : [ptr]) switch (type) {
              case "i1":
              case "i8":
                c.HEAP8[Number(p) >> 0] = value;
                continue;
              case "i16":
                c.HEAP16[Number(p) >> 1] = value;
                continue;
              case "i32":
                c.HEAP32[Number(p) >> 2] = value;
                continue;
              case "float":
              case "f32":
                c.HEAP32F[Number(p) >> 2] = value;
                continue;
              case "double":
              case "f64":
                c.HEAP64F[Number(p) >> 3] = value;
                continue;
              case "i64":
                if (c.HEAP64) {
                  c.HEAP64[Number(p) >> 3] = __BigInt(value);
                  continue;
                }
              default:
                toss("Invalid type for poke(): " + type);
            }
            return this;
          };
          target.peekPtr = (...ptr) => target.peek(1 === ptr.length ? ptr[0] : ptr, __ptrIR);
          target.pokePtr = (ptr, value = 0) => target.poke(ptr, value, __ptrIR);
          target.peek8 = (...ptr) => target.peek(1 === ptr.length ? ptr[0] : ptr, "i8");
          target.poke8 = (ptr, value) => target.poke(ptr, value, "i8");
          target.peek16 = (...ptr) => target.peek(1 === ptr.length ? ptr[0] : ptr, "i16");
          target.poke16 = (ptr, value) => target.poke(ptr, value, "i16");
          target.peek32 = (...ptr) => target.peek(1 === ptr.length ? ptr[0] : ptr, "i32");
          target.poke32 = (ptr, value) => target.poke(ptr, value, "i32");
          target.peek64 = (...ptr) => target.peek(1 === ptr.length ? ptr[0] : ptr, "i64");
          target.poke64 = (ptr, value) => target.poke(ptr, value, "i64");
          target.peek32f = (...ptr) => target.peek(1 === ptr.length ? ptr[0] : ptr, "f32");
          target.poke32f = (ptr, value) => target.poke(ptr, value, "f32");
          target.peek64f = (...ptr) => target.peek(1 === ptr.length ? ptr[0] : ptr, "f64");
          target.poke64f = (ptr, value) => target.poke(ptr, value, "f64");
          target.getMemValue = target.peek;
          target.getPtrValue = target.peekPtr;
          target.setMemValue = target.poke;
          target.setPtrValue = target.pokePtr;
          target.isPtr32 = ptr => "number" === typeof ptr && ptr >= 0 && ptr === (ptr | 0);
          target.isPtr64 = ptr => "bigint" === typeof ptr ? ptr >= 0 : target.isPtr32(ptr);
          target.isPtr = 4 === __ptrSize ? target.isPtr32 : target.isPtr64;
          target.cstrlen = function (ptr) {
            if (!ptr || !target.isPtr(ptr)) return null;
            ptr = Number(ptr);
            const h = heapWrappers().HEAP8U;
            let pos = ptr;
            for (; h[pos] !== 0; ++pos);
            return pos - ptr;
          };
          const __SAB = "undefined" === typeof SharedArrayBuffer ? function () {} : SharedArrayBuffer;
          const isSharedTypedArray = aTypedArray => aTypedArray.buffer instanceof __SAB;
          target.isSharedTypedArray = isSharedTypedArray;
          const typedArrayPart = (aTypedArray, begin, end) => {
            if (8 === __ptrSize) {
              if ("bigint" === typeof begin) begin = Number(begin);
              if ("bigint" === typeof end) end = Number(end);
            }
            return isSharedTypedArray(aTypedArray) ? aTypedArray.slice(begin, end) : aTypedArray.subarray(begin, end);
          };
          target.typedArrayPart = typedArrayPart;
          const typedArrayToString = (typedArray, begin, end) => cache.utf8Decoder.decode(typedArrayPart(typedArray, begin, end));
          target.typedArrayToString = typedArrayToString;
          target.cstrToJs = function (ptr) {
            const n = target.cstrlen(ptr);
            return n ? typedArrayToString(heapWrappers().HEAP8U, Number(ptr), Number(ptr) + n) : null === n ? n : "";
          };
          target.jstrlen = function (str) {
            if ("string" !== typeof str) return null;
            const n = str.length;
            let len = 0;
            for (let i = 0; i < n; ++i) {
              let u = str.charCodeAt(i);
              if (u >= 55296 && u <= 57343) u = 65536 + ((u & 1023) << 10) | str.charCodeAt(++i) & 1023;
              if (u <= 127) ++len;else if (u <= 2047) len += 2;else if (u <= 65535) len += 3;else len += 4;
            }
            return len;
          };
          target.jstrcpy = function (jstr, tgt, offset = 0, maxBytes = -1, addNul = true) {
            if (!tgt || !(tgt instanceof Int8Array) && !(tgt instanceof Uint8Array)) toss("jstrcpy() target must be an Int8Array or Uint8Array.");
            maxBytes = Number(maxBytes);
            offset = Number(offset);
            if (maxBytes < 0) maxBytes = tgt.length - offset;
            if (!(maxBytes > 0) || !(offset >= 0)) return 0;
            let i = 0,
              max = jstr.length;
            const begin = offset,
              end = offset + maxBytes - (addNul ? 1 : 0);
            for (; i < max && offset < end; ++i) {
              let u = jstr.charCodeAt(i);
              if (u >= 55296 && u <= 57343) u = 65536 + ((u & 1023) << 10) | jstr.charCodeAt(++i) & 1023;
              if (u <= 127) {
                if (offset >= end) break;
                tgt[offset++] = u;
              } else if (u <= 2047) {
                if (offset + 1 >= end) break;
                tgt[offset++] = 192 | u >> 6;
                tgt[offset++] = 128 | u & 63;
              } else if (u <= 65535) {
                if (offset + 2 >= end) break;
                tgt[offset++] = 224 | u >> 12;
                tgt[offset++] = 128 | u >> 6 & 63;
                tgt[offset++] = 128 | u & 63;
              } else {
                if (offset + 3 >= end) break;
                tgt[offset++] = 240 | u >> 18;
                tgt[offset++] = 128 | u >> 12 & 63;
                tgt[offset++] = 128 | u >> 6 & 63;
                tgt[offset++] = 128 | u & 63;
              }
            }
            if (addNul) tgt[offset++] = 0;
            return offset - begin;
          };
          target.cstrncpy = function (tgtPtr, srcPtr, n) {
            if (!tgtPtr || !srcPtr) toss("cstrncpy() does not accept NULL strings.");
            if (n < 0) n = target.cstrlen(strPtr) + 1;else if (!(n > 0)) return 0;
            const heap = target.heap8u();
            let i = 0,
              ch;
            const tgtNumber = Number(tgtPtr),
              srcNumber = Number(srcPtr);
            for (; i < n && (ch = heap[srcNumber + i]); ++i) heap[tgtNumber + i] = ch;
            if (i < n) heap[tgtNumber + i++] = 0;
            return i;
          };
          target.jstrToUintArray = (str, addNul = false) => {
            return cache.utf8Encoder.encode(addNul ? str + "\0" : str);
          };
          const __affirmAlloc = (obj, funcName) => {
            if (!(obj.alloc instanceof Function) || !(obj.dealloc instanceof Function)) toss("Object is missing alloc() and/or dealloc() function(s)", "required by", funcName + "().");
          };
          const __allocCStr = function (jstr, returnWithLength, allocator, funcName) {
            __affirmAlloc(target, funcName);
            if ("string" !== typeof jstr) return null;
            const u = cache.utf8Encoder.encode(jstr),
              ptr = allocator(u.length + 1);
            let toFree = ptr;
            try {
              const heap = heapWrappers().HEAP8U;
              heap.set(u, Number(ptr));
              heap[__ptrAdd(ptr, u.length)] = 0;
              toFree = __NullPtr;
              return returnWithLength ? [ptr, u.length] : ptr;
            } finally {
              if (toFree) target.dealloc(toFree);
            }
          };
          target.allocCString = (jstr, returnWithLength = false) => __allocCStr(jstr, returnWithLength, target.alloc, "allocCString()");
          target.scopedAllocPush = function () {
            __affirmAlloc(target, "scopedAllocPush");
            const a = [];
            cache.scopedAlloc.push(a);
            return a;
          };
          target.scopedAllocPop = function (state) {
            __affirmAlloc(target, "scopedAllocPop");
            const n = arguments.length ? cache.scopedAlloc.indexOf(state) : cache.scopedAlloc.length - 1;
            if (n < 0) toss("Invalid state object for scopedAllocPop().");
            if (0 === arguments.length) state = cache.scopedAlloc[n];
            cache.scopedAlloc.splice(n, 1);
            for (let p; p = state.pop();) if (target.functionEntry(p)) target.uninstallFunction(p);else target.dealloc(p);
          };
          target.scopedAlloc = function (n) {
            if (!cache.scopedAlloc.length) toss("No scopedAllocPush() scope is active.");
            const p = __asPtrType(target.alloc(n));
            return cache.scopedAlloc.pushPtr(p);
          };
          Object.defineProperty(target.scopedAlloc, "level", {
            configurable: false,
            enumerable: false,
            get: () => cache.scopedAlloc.length,
            set: () => toss("The 'active' property is read-only.")
          });
          target.scopedAllocCString = (jstr, returnWithLength = false) => __allocCStr(jstr, returnWithLength, target.scopedAlloc, "scopedAllocCString()");
          const __allocMainArgv = function (isScoped, list) {
            const pList = target[isScoped ? "scopedAlloc" : "alloc"]((list.length + 1) * target.ptr.size);
            let i = 0;
            list.forEach(e => {
              target.pokePtr(__ptrAdd(pList, target.ptr.size * i++), target[isScoped ? "scopedAllocCString" : "allocCString"]("" + e));
            });
            target.pokePtr(__ptrAdd(pList, target.ptr.size * i), 0);
            return pList;
          };
          target.scopedAllocMainArgv = list => __allocMainArgv(true, list);
          target.allocMainArgv = list => __allocMainArgv(false, list);
          target.cArgvToJs = (argc, pArgv) => {
            const list = [];
            for (let i = 0; i < argc; ++i) {
              const arg = target.peekPtr(__ptrAdd(pArgv, target.ptr.size * i));
              list.push(arg ? target.cstrToJs(arg) : null);
            }
            return list;
          };
          target.scopedAllocCall = function (func) {
            target.scopedAllocPush();
            try {
              return func();
            } finally {
              target.scopedAllocPop();
            }
          };
          const __allocPtr = function (howMany, safePtrSize, method) {
            __affirmAlloc(target, method);
            const pIr = safePtrSize ? "i64" : __ptrIR;
            let m = target[method](howMany * (safePtrSize ? 8 : __ptrSize));
            target.poke(m, 0, pIr);
            if (1 === howMany) return m;
            const a = [m];
            for (let i = 1; i < howMany; ++i) {
              m = __ptrAdd(m, safePtrSize ? 8 : __ptrSize);
              a[i] = m;
              target.poke(m, 0, pIr);
            }
            return a;
          };
          target.allocPtr = (howMany = 1, safePtrSize = true) => __allocPtr(howMany, safePtrSize, "alloc");
          target.scopedAllocPtr = (howMany = 1, safePtrSize = true) => __allocPtr(howMany, safePtrSize, "scopedAlloc");
          target.xGet = function (name) {
            return target.exports[name] || toss("Cannot find exported symbol:", name);
          };
          const __argcMismatch = (f, n) => toss(f + "() requires", n, "argument(s).");
          target.xCall = function (fname, ...args) {
            const f = fname instanceof Function ? fname : target.xGet(fname);
            if (!(f instanceof Function)) toss("Exported symbol", fname, "is not a function.");
            if (f.length !== args.length) __argcMismatch(f === fname ? f.name : fname, f.length);
            return 2 === arguments.length && Array.isArray(arguments[1]) ? f.apply(null, arguments[1]) : f.apply(null, args);
          };
          cache.xWrap = Object.create(null);
          cache.xWrap.convert = Object.create(null);
          cache.xWrap.convert.arg = /* @__PURE__ */new Map();
          cache.xWrap.convert.result = /* @__PURE__ */new Map();
          const xArg = cache.xWrap.convert.arg,
            xResult = cache.xWrap.convert.result;
          const __xArgPtr = __asPtrType;
          xArg.set("i64", __BigInt).set("i32", i => i | 0).set("i16", i => (i | 0) & 65535).set("i8", i => (i | 0) & 255).set("f32", i => Number(i).valueOf()).set("float", xArg.get("f32")).set("f64", xArg.get("f32")).set("double", xArg.get("f64")).set("int", xArg.get("i32")).set("null", i => i).set(null, xArg.get("null")).set("**", __xArgPtr).set("*", __xArgPtr);
          xResult.set("*", __xArgPtr).set("pointer", __xArgPtr).set("number", v => Number(v)).set("void", v => void 0).set(void 0, xResult.get("void")).set("null", v => v).set(null, xResult.get("null"));
          for (const t of ["i8", "i16", "i32", "i64", "int", "f32", "float", "f64", "double"]) {
            xArg.set(t + "*", __xArgPtr);
            xResult.set(t + "*", __xArgPtr);
            xResult.set(t, xArg.get(t) || toss("Maintenance required: missing arg converter for", t));
          }
          const __xArgString = v => {
            return "string" === typeof v ? target.scopedAllocCString(v) : __asPtrType(v);
          };
          xArg.set("string", __xArgString).set("utf8", __xArgString);
          xResult.set("string", i => target.cstrToJs(i)).set("utf8", xResult.get("string")).set("string:dealloc", i => {
            try {
              return i ? target.cstrToJs(i) : null;
            } finally {
              target.dealloc(i);
            }
          }).set("utf8:dealloc", xResult.get("string:dealloc")).set("json", i => JSON.parse(target.cstrToJs(i))).set("json:dealloc", i => {
            try {
              return i ? JSON.parse(target.cstrToJs(i)) : null;
            } finally {
              target.dealloc(i);
            }
          });
          const AbstractArgAdapter = class {
            constructor(opt) {
              this.name = opt.name || "unnamed adapter";
            }
            convertArg(v, argv, argIndex) {
              toss("AbstractArgAdapter must be subclassed.");
            }
          };
          xArg.FuncPtrAdapter = class FuncPtrAdapter extends AbstractArgAdapter {
            constructor(opt) {
              super(opt);
              if (xArg.FuncPtrAdapter.warnOnUse) console.warn("xArg.FuncPtrAdapter is an internal-only API", "and is not intended to be invoked from", "client-level code. Invoked with:", opt);
              this.name = opt.name || "unnamed";
              this.signature = opt.signature;
              if (opt.contextKey instanceof Function) {
                this.contextKey = opt.contextKey;
                if (!opt.bindScope) opt.bindScope = "context";
              }
              this.bindScope = opt.bindScope || toss("FuncPtrAdapter options requires a bindScope (explicit or implied).");
              if (FuncPtrAdapter.bindScopes.indexOf(opt.bindScope) < 0) toss("Invalid options.bindScope (" + opt.bindMod + ") for FuncPtrAdapter. Expecting one of: (" + FuncPtrAdapter.bindScopes.join(", ") + ")");
              this.isTransient = "transient" === this.bindScope;
              this.isContext = "context" === this.bindScope;
              this.isPermanent = "permanent" === this.bindScope;
              this.singleton = "singleton" === this.bindScope ? [] : void 0;
              this.callProxy = opt.callProxy instanceof Function ? opt.callProxy : void 0;
            }
            contextKey(argv, argIndex) {
              return this;
            }
            contextMap(key) {
              const cm = this.__cmap || (this.__cmap = /* @__PURE__ */new Map());
              let rc = cm.get(key);
              if (void 0 === rc) cm.set(key, rc = []);
              return rc;
            }
            convertArg(v, argv, argIndex) {
              let pair = this.singleton;
              if (!pair && this.isContext) pair = this.contextMap(this.contextKey(argv, argIndex));
              if (pair && 2 === pair.length && pair[0] === v) return pair[1];
              if (v instanceof Function) {
                if (this.callProxy) v = this.callProxy(v);
                const fp = __installFunction(v, this.signature, this.isTransient);
                if (FuncPtrAdapter.debugFuncInstall) FuncPtrAdapter.debugOut("FuncPtrAdapter installed", this, this.contextKey(argv, argIndex), "@" + fp, v);
                if (pair) {
                  if (pair[1]) {
                    if (FuncPtrAdapter.debugFuncInstall) FuncPtrAdapter.debugOut("FuncPtrAdapter uninstalling", this, this.contextKey(argv, argIndex), "@" + pair[1], v);
                    try {
                      cache.scopedAlloc.pushPtr(pair[1]);
                    } catch (e) {}
                  }
                  pair[0] = arguments[0] || __NullPtr;
                  pair[1] = fp;
                }
                return fp;
              } else if (target.isPtr(v) || null === v || void 0 === v) {
                if (pair && pair[1] && pair[1] !== v) {
                  if (FuncPtrAdapter.debugFuncInstall) FuncPtrAdapter.debugOut("FuncPtrAdapter uninstalling", this, this.contextKey(argv, argIndex), "@" + pair[1], v);
                  try {
                    cache.scopedAlloc.pushPtr(pair[1]);
                  } catch (e) {}
                  pair[0] = pair[1] = v || __NullPtr;
                }
                return v || __NullPtr;
              } else throw new TypeError("Invalid FuncPtrAdapter argument type. Expecting a function pointer or a " + (this.name ? this.name + " " : "") + "function matching signature " + this.signature + ".");
            }
          };
          xArg.FuncPtrAdapter.warnOnUse = false;
          xArg.FuncPtrAdapter.debugFuncInstall = false;
          xArg.FuncPtrAdapter.debugOut = console.debug.bind(console);
          xArg.FuncPtrAdapter.bindScopes = ["transient", "context", "singleton", "permanent"];
          const __xArgAdapterCheck = t => xArg.get(t) || toss("Argument adapter not found:", t);
          const __xResultAdapterCheck = t => xResult.get(t) || toss("Result adapter not found:", t);
          cache.xWrap.convertArg = (t, ...args) => __xArgAdapterCheck(t)(...args);
          cache.xWrap.convertArgNoCheck = (t, ...args) => xArg.get(t)(...args);
          cache.xWrap.convertResult = (t, v) => null === t ? v : t ? __xResultAdapterCheck(t)(v) : void 0;
          cache.xWrap.convertResultNoCheck = (t, v) => null === t ? v : t ? xResult.get(t)(v) : void 0;
          target.xWrap = function callee(fArg, resultType, ...argTypes) {
            if (3 === arguments.length && Array.isArray(arguments[2])) argTypes = arguments[2];
            if (target.isPtr(fArg)) fArg = target.functionEntry(fArg) || toss("Function pointer not found in WASM function table.");
            const fIsFunc = fArg instanceof Function;
            const xf = fIsFunc ? fArg : target.xGet(fArg);
            if (fIsFunc) fArg = xf.name || "unnamed function";
            if (argTypes.length !== xf.length) __argcMismatch(fArg, xf.length);
            if (0 === xf.length && (null === resultType || "null" === resultType)) return xf;
            __xResultAdapterCheck(resultType);
            for (const t of argTypes) if (t instanceof AbstractArgAdapter) xArg.set(t, (...args) => t.convertArg(...args));else __xArgAdapterCheck(t);
            const cxw = cache.xWrap;
            if (0 === xf.length) return (...args) => args.length ? __argcMismatch(fArg, xf.length) : cxw.convertResult(resultType, xf.call(null));
            return function (...args) {
              if (args.length !== xf.length) __argcMismatch(fArg, xf.length);
              const scope = target.scopedAllocPush();
              try {
                let i = 0;
                if (callee.debug) console.debug("xWrap() preparing: resultType ", resultType, "xf", xf, "argTypes", argTypes, "args", args);
                for (; i < args.length; ++i) args[i] = cxw.convertArgNoCheck(argTypes[i], args[i], args, i);
                if (callee.debug) console.debug("xWrap() calling: resultType ", resultType, "xf", xf, "argTypes", argTypes, "args", args);
                return cxw.convertResultNoCheck(resultType, xf.apply(null, args));
              } finally {
                target.scopedAllocPop(scope);
              }
            };
          };
          const __xAdapter = function (func, argc, typeName, adapter, modeName, xcvPart) {
            if ("string" === typeof typeName) {
              if (1 === argc) return xcvPart.get(typeName);else if (2 === argc) {
                if (!adapter) {
                  xcvPart.delete(typeName);
                  return func;
                } else if (!(adapter instanceof Function)) toss(modeName, "requires a function argument.");
                xcvPart.set(typeName, adapter);
                return func;
              }
            }
            toss("Invalid arguments to", modeName);
          };
          target.xWrap.resultAdapter = function f(typeName, adapter) {
            return __xAdapter(f, arguments.length, typeName, adapter, "resultAdapter()", xResult);
          };
          target.xWrap.argAdapter = function f(typeName, adapter) {
            return __xAdapter(f, arguments.length, typeName, adapter, "argAdapter()", xArg);
          };
          target.xWrap.FuncPtrAdapter = xArg.FuncPtrAdapter;
          target.xCallWrapped = function (fArg, resultType, argTypes, ...args) {
            if (Array.isArray(arguments[3])) args = arguments[3];
            return target.xWrap(fArg, resultType, argTypes || []).apply(null, args || []);
          };
          target.xWrap.testConvertArg = cache.xWrap.convertArg;
          target.xWrap.testConvertResult = cache.xWrap.convertResult;
          return target;
        };
        globalThis.WhWasmUtilInstaller.yawl = function yawl(config) {

          const wfetch = () => fetch(config.uri, {
            credentials: "same-origin"
          });
          const wui = this;
          const finalThen = function (arg) {
            if (config.wasmUtilTarget) {
              const toss = (...args) => {
                throw new Error(args.join(" "));
              };
              const tgt = config.wasmUtilTarget;
              tgt.module = arg.module;
              tgt.instance = arg.instance;
              if (!tgt.instance.exports.memory) tgt.memory = config?.imports?.env?.memory || toss("Missing 'memory' object!");
              if (!tgt.alloc && arg.instance.exports.malloc) {
                const exports$1 = arg.instance.exports;
                tgt.alloc = function (n) {
                  return exports$1.malloc(n) || toss("Allocation of", n, "bytes failed.");
                };
                tgt.dealloc = function (m) {
                  m && exports$1.free(m);
                };
              }
              wui(tgt);
            }
            arg.config = config;
            if (config.onload) config.onload(arg);
            return arg;
          };
          return WebAssembly.instantiateStreaming ? () => WebAssembly.instantiateStreaming(wfetch(), config.imports || {}).then(finalThen) : () => wfetch().then(response => response.arrayBuffer()).then(bytes => WebAssembly.instantiate(bytes, config.imports || {})).then(finalThen);
        }.bind(globalThis.WhWasmUtilInstaller);
        globalThis.Jaccwabyt = function StructBinderFactory(config) {

          const toss = (...args) => {
            throw new Error(args.join(" "));
          };
          {
            let h = config.heap;
            if (h instanceof WebAssembly.Memory) h = function () {
              return new Uint8Array(this.buffer);
            }.bind(h);else if (!(h instanceof Function)) toss("config.heap must be WebAssembly.Memory instance or", "a function which returns one.");
            config.heap = h;
          }
          ["alloc", "dealloc"].forEach(function (k) {
            config[k] instanceof Function || toss("Config option '" + k + "' must be a function.");
          });
          const SBF = StructBinderFactory,
            heap = config.heap,
            alloc = config.alloc,
            dealloc = config.dealloc;
          config.realloc;
          const log = config.log || console.debug.bind(console),
            memberPrefix = config.memberPrefix || "",
            memberSuffix = config.memberSuffix || "",
            BigInt = globalThis["BigInt"],
            BigInt64Array = globalThis["BigInt64Array"],
            bigIntEnabled = config.bigIntEnabled ?? !!BigInt64Array;
          let ptr;
          const ptrSize = config.pointerSize || config.ptrSize || ("bigint" === typeof (ptr = alloc(1)) ? 8 : 4);
          const ptrIR = config.pointerIR || config.ptrIR || (4 === ptrSize ? "i32" : "i64");
          if (ptr) {
            dealloc(ptr);
            ptr = void 0;
          }
          if (ptrSize !== 4 && ptrSize !== 8) toss("Invalid pointer size:", ptrSize);
          if (ptrIR !== "i32" && ptrIR !== "i64") toss("Invalid pointer representation:", ptrIR);
          const __BigInt = bigIntEnabled && BigInt ? v => BigInt(v || 0) : v => toss("BigInt support is disabled in this build.");
          const __asPtrType = "i32" == ptrIR ? Number : __BigInt;
          const __NullPtr = __asPtrType(0);
          const __ptrAdd = function (...args) {
            let rc = __NullPtr;
            for (let i = 0; i < args.length; ++i) rc += __asPtrType(args[i]);
            return rc;
          };
          const __ptrAddSelf = function (...args) {
            return __ptrAdd(this.pointer, ...args);
          };
          if (!SBF.debugFlags) {
            SBF.__makeDebugFlags = function (deriveFrom = null) {
              if (deriveFrom && deriveFrom.__flags) deriveFrom = deriveFrom.__flags;
              const f = function f(flags) {
                if (0 === arguments.length) return f.__flags;
                if (flags < 0) {
                  delete f.__flags.getter;
                  delete f.__flags.setter;
                  delete f.__flags.alloc;
                  delete f.__flags.dealloc;
                } else {
                  f.__flags.getter = 0 !== (1 & flags);
                  f.__flags.setter = 0 !== (2 & flags);
                  f.__flags.alloc = 0 !== (4 & flags);
                  f.__flags.dealloc = 0 !== (8 & flags);
                }
                return f._flags;
              };
              Object.defineProperty(f, "__flags", {
                iterable: false,
                writable: false,
                value: Object.create(deriveFrom)
              });
              if (!deriveFrom) f(0);
              return f;
            };
            SBF.debugFlags = SBF.__makeDebugFlags();
          }
          const isLittleEndian = true;
          const isFuncSig = s => "(" === s[1];
          const isPtrSig = s => "p" === s || "P" === s || "s" === s;
          const isAutoPtrSig = s => "P" === s;
          const sigLetter = s => s ? isFuncSig(s) ? "p" : s[0] : void 0;
          const sigIR = function (s) {
            switch (sigLetter(s)) {
              case "c":
              case "C":
                return "i8";
              case "i":
                return "i32";
              case "p":
              case "P":
              case "s":
                return ptrIR;
              case "j":
                return "i64";
              case "f":
                return "float";
              case "d":
                return "double";
            }
            toss("Unhandled signature IR:", s);
          };
          const sigSize = function (s) {
            switch (sigLetter(s)) {
              case "c":
              case "C":
                return 1;
              case "i":
                return 4;
              case "p":
              case "P":
              case "s":
                return ptrSize;
              case "j":
                return 8;
              case "f":
                return 4;
              case "d":
                return 8;
            }
            toss("Unhandled signature sizeof:", s);
          };
          const affirmBigIntArray = BigInt64Array ? () => true : () => toss("BigInt64Array is not available.");
          const sigDVGetter = function (s) {
            switch (sigLetter(s)) {
              case "p":
              case "P":
              case "s":
                switch (ptrSize) {
                  case 4:
                    return "getInt32";
                  case 8:
                    return affirmBigIntArray() && "getBigInt64";
                }
                break;
              case "i":
                return "getInt32";
              case "c":
                return "getInt8";
              case "C":
                return "getUint8";
              case "j":
                return affirmBigIntArray() && "getBigInt64";
              case "f":
                return "getFloat32";
              case "d":
                return "getFloat64";
            }
            toss("Unhandled DataView getter for signature:", s);
          };
          const sigDVSetter = function (s) {
            switch (sigLetter(s)) {
              case "p":
              case "P":
              case "s":
                switch (ptrSize) {
                  case 4:
                    return "setInt32";
                  case 8:
                    return affirmBigIntArray() && "setBigInt64";
                }
                break;
              case "i":
                return "setInt32";
              case "c":
                return "setInt8";
              case "C":
                return "setUint8";
              case "j":
                return affirmBigIntArray() && "setBigInt64";
              case "f":
                return "setFloat32";
              case "d":
                return "setFloat64";
            }
            toss("Unhandled DataView setter for signature:", s);
          };
          const sigDVSetWrapper = function (s) {
            switch (sigLetter(s)) {
              case "i":
              case "f":
              case "c":
              case "C":
              case "d":
                return Number;
              case "j":
                return __BigInt;
              case "p":
              case "P":
              case "s":
                switch (ptrSize) {
                  case 4:
                    return Number;
                  case 8:
                    return __BigInt;
                }
                break;
            }
            toss("Unhandled DataView set wrapper for signature:", s);
          };
          const sPropName = (s, k) => s + "::" + k;
          const __propThrowOnSet = function (structName, propName) {
            return () => toss(sPropName(structName, propName), "is read-only.");
          };
          const getInstanceHandle = function f(obj, create = true) {
            let ii = f.map.get(obj);
            if (!ii && create) f.map.set(obj, ii = f.create(obj));
            return ii;
          };
          getInstanceHandle.map = /* @__PURE__ */new WeakMap();
          getInstanceHandle.create = forObj => {
            return Object.assign(Object.create(null), {
              o: forObj,
              p: void 0,
              ownsPointer: false,
              zod: false,
              xb: 0
            });
          };
          const rmInstanceHandle = obj => getInstanceHandle.map.delete(obj);
          const __isPtr32 = ptr => "number" === typeof ptr && ptr === (ptr | 0) && ptr >= 0;
          const __isPtr64 = ptr => "bigint" === typeof ptr && ptr >= 0 || __isPtr32(ptr);
          const __isPtr = 4 === ptrSize ? __isPtr32 : __isPtr64;
          const __isNonNullPtr = v => __isPtr(v) && v > 0;
          const __freeStruct = function (ctor, obj, m) {
            const ii = getInstanceHandle(obj, false);
            if (!ii) return;
            rmInstanceHandle(obj);
            if (!m && !(m = ii.p)) {
              console.warn("Cannot(?) happen: __freeStruct() found no instanceInfo");
              return;
            }
            if (Array.isArray(obj.ondispose)) {
              let x;
              while (x = obj.ondispose.pop()) try {
                if (x instanceof Function) x.call(obj);else if (x instanceof StructType) x.dispose();else if (__isPtr(x)) dealloc(x);
              } catch (e) {
                console.warn("ondispose() for", ctor.structName, "@", m, "threw. NOT propagating it.", e);
              }
            } else if (obj.ondispose instanceof Function) try {
              obj.ondispose();
            } catch (e) {
              console.warn("ondispose() for", ctor.structName, "@", m, "threw. NOT propagating it.", e);
            }
            delete obj.ondispose;
            if (ctor.debugFlags.__flags.dealloc) log("debug.dealloc:", ii.ownsPointer ? "" : "EXTERNAL", ctor.structName, "instance:", ctor.structInfo.sizeof, "bytes @" + m);
            if (ii.ownsPointer) {
              if (ii.zod || ctor.structInfo.zeroOnDispose) heap().fill(0, Number(m), Number(m) + ctor.structInfo.sizeof + ii.xb);
              dealloc(m);
            }
          };
          const rop0 = () => {
            return {
              configurable: false,
              writable: false,
              iterable: false
            };
          };
          const rop = v => {
            return {
              ...rop0(),
              value: v
            };
          };
          const __allocStruct = function f(ctor, obj, xm) {
            let opt;
            const checkPtr = ptr => {
              __isNonNullPtr(ptr) || toss("Invalid pointer value", arguments[0], "for", ctor.structName, "constructor.");
            };
            if (arguments.length >= 3) {
              if (xm && "object" === typeof xm) {
                opt = xm;
                xm = opt?.wrap;
              } else {
                checkPtr(xm);
                opt = {
                  wrap: xm
                };
              }
            } else opt = {};
            const fill = !xm;
            let nAlloc = 0;
            let ownsPointer = false;
            if (xm) {
              checkPtr(xm);
              ownsPointer = !!opt?.takeOwnership;
            } else {
              const nX = opt?.extraBytes ?? 0;
              if (nX < 0 || nX !== (nX | 0)) toss("Invalid extraBytes value:", opt?.extraBytes);
              nAlloc = ctor.structInfo.sizeof + nX;
              xm = alloc(nAlloc) || toss("Allocation of", ctor.structName, "structure failed.");
              ownsPointer = true;
            }
            try {
              if (opt?.debugFlags) obj.debugFlags(opt.debugFlags);
              if (ctor.debugFlags.__flags.alloc) log("debug.alloc:", fill ? "" : "EXTERNAL", ctor.structName, "instance:", ctor.structInfo.sizeof, "bytes @" + xm);
              if (fill) heap().fill(0, Number(xm), Number(xm) + nAlloc);
              const ii = getInstanceHandle(obj);
              ii.p = xm;
              ii.ownsPointer = ownsPointer;
              ii.xb = nAlloc ? nAlloc - ctor.structInfo.sizeof : 0;
              ii.zod = !!opt?.zeroOnDispose;
              if (opt?.ondispose && opt.ondispose !== xm) obj.addOnDispose(opt.ondispose);
            } catch (e) {
              __freeStruct(ctor, obj, xm);
              throw e;
            }
          };
          const looksLikeASig = function f(sig) {
            f.rxSig1 ??= /^[ipPsjfdcC]$/;
            f.rxSig2 ??= /^[vipPsjfdcC]\([ipPsjfdcC]*\)$/;
            return f.rxSig1.test(sig) || f.rxSig2.test(sig);
          };
          const __adaptorsFor = function (who) {
            let x = this.get(who);
            if (!x) {
              x = [Object.create(null), Object.create(null), Object.create(null)];
              this.set(who, x);
            }
            return x;
          }.bind(/* @__PURE__ */new WeakMap());
          const __adaptor = function (who, which, key, proxy) {
            const a = __adaptorsFor(who)[which];
            if (3 === arguments.length) return a[key];
            if (proxy) return a[key] = proxy;
            return delete a[key];
          };
          const __adaptGet = function (key, ...args) {
            return __adaptor(this, 0, key, ...args);
          };
          const __affirmNotASig = function (ctx, key) {
            looksLikeASig(key) && toss(ctx, "(", key, ") collides with a data type signature.");
          };
          const __adaptSet = function (key, ...args) {
            __affirmNotASig("Setter adaptor", key);
            return __adaptor(this, 1, key, ...args);
          };
          const __adaptStruct = function (key, ...args) {
            __affirmNotASig("Struct adaptor", key);
            return __adaptor(this, 2, key, ...args);
          };
          const __adaptStruct2 = function (who, key) {
            const si = "string" === typeof key ? __adaptor(who, 2, key) : key;
            if ("object" !== typeof si) toss("Invalid struct mapping object. Arg =", key, JSON.stringify(si));
            return si;
          };
          const __memberKey = k => memberPrefix + k + memberSuffix;
          const __memberKeyProp = rop(__memberKey);
          const __lookupMember = function (structInfo, memberName, tossIfNotFound = true) {
            let m = structInfo.members[memberName];
            if (!m && (memberPrefix || memberSuffix)) {
              for (const v of Object.values(structInfo.members)) if (v.key === memberName) {
                m = v;
                break;
              }
              if (!m && tossIfNotFound) toss(sPropName(structInfo.name || structInfo.structName, memberName), "is not a mapped struct member.");
            }
            return m;
          };
          const __memberSignature = function f(obj, memberName, emscriptenFormat = false) {
            if (!f._) f._ = x => x.replace(/[^vipPsjrdcC]/g, "").replace(/[pPscC]/g, "i");
            const m = __lookupMember(obj.structInfo, memberName, true);
            return emscriptenFormat ? f._(m.signature) : m.signature;
          };
          const __structMemberKeys = rop(function () {
            const a = [];
            for (const k of Object.keys(this.structInfo.members)) a.push(this.memberKey(k));
            return a;
          });
          const __utf8Decoder = new TextDecoder("utf-8");
          const __utf8Encoder = new TextEncoder();
          const __SAB = "undefined" === typeof SharedArrayBuffer ? function () {} : SharedArrayBuffer;
          const __utf8Decode = function (arrayBuffer, begin, end) {
            if (8 === ptrSize) {
              begin = Number(begin);
              end = Number(end);
            }
            return __utf8Decoder.decode(arrayBuffer.buffer instanceof __SAB ? arrayBuffer.slice(begin, end) : arrayBuffer.subarray(begin, end));
          };
          const __memberIsString = function (obj, memberName, tossIfNotFound = false) {
            const m = __lookupMember(obj.structInfo, memberName, tossIfNotFound);
            return m && 1 === m.signature.length && "s" === m.signature[0] ? m : false;
          };
          const __affirmCStringSignature = function (member) {
            if ("s" === member.signature) return;
            toss("Invalid member type signature for C-string value:", JSON.stringify(member));
          };
          const __memberToJsString = function f(obj, memberName) {
            const m = __lookupMember(obj.structInfo, memberName, true);
            __affirmCStringSignature(m);
            const addr = obj[m.key];
            if (!addr) return null;
            let pos = addr;
            const mem = heap();
            for (; mem[pos] !== 0; ++pos);
            return addr === pos ? "" : __utf8Decode(mem, addr, pos);
          };
          const __addOnDispose = function (obj, ...v) {
            if (obj.ondispose) {
              if (!Array.isArray(obj.ondispose)) obj.ondispose = [obj.ondispose];
            } else obj.ondispose = [];
            obj.ondispose.push(...v);
          };
          const __allocCString = function (str) {
            const u = __utf8Encoder.encode(str);
            const mem = alloc(u.length + 1);
            if (!mem) toss("Allocation error while duplicating string:", str);
            const h = heap();
            h.set(u, Number(mem));
            h[__ptrAdd(mem, u.length)] = 0;
            return mem;
          };
          const __setMemberCString = function (obj, memberName, str) {
            const m = __lookupMember(obj.structInfo, memberName, true);
            __affirmCStringSignature(m);
            const mem = __allocCString(str);
            obj[m.key] = mem;
            __addOnDispose(obj, mem);
            return obj;
          };
          const StructType = function StructType(structName, structInfo) {
            if (arguments[2] !== rop) toss("Do not call the StructType constructor", "from client-level code.");
            Object.defineProperties(this, {
              structName: rop(structName),
              structInfo: rop(structInfo)
            });
          };
          StructType.prototype = Object.create(null, {
            dispose: rop(function () {
              __freeStruct(this.constructor, this);
            }),
            lookupMember: rop(function (memberName, tossIfNotFound = true) {
              return __lookupMember(this.structInfo, memberName, tossIfNotFound);
            }),
            memberToJsString: rop(function (memberName) {
              return __memberToJsString(this, memberName);
            }),
            memberIsString: rop(function (memberName, tossIfNotFound = true) {
              return __memberIsString(this, memberName, tossIfNotFound);
            }),
            memberKey: __memberKeyProp,
            memberKeys: __structMemberKeys,
            memberSignature: rop(function (memberName, emscriptenFormat = false) {
              return __memberSignature(this, memberName, emscriptenFormat);
            }),
            memoryDump: rop(function () {
              const p = this.pointer;
              return p ? new Uint8Array(heap().slice(Number(p), Number(p) + this.structInfo.sizeof)) : null;
            }),
            extraBytes: {
              configurable: false,
              enumerable: false,
              get: function () {
                return getInstanceHandle(this, false)?.xb ?? 0;
              }
            },
            zeroOnDispose: {
              configurable: false,
              enumerable: false,
              get: function () {
                return getInstanceHandle(this, false)?.zod ?? !!this.structInfo.zeroOnDispose;
              }
            },
            pointer: {
              configurable: false,
              enumerable: false,
              get: function () {
                return getInstanceHandle(this, false)?.p;
              },
              set: () => toss("Cannot assign the 'pointer' property of a struct.")
            },
            setMemberCString: rop(function (memberName, str) {
              return __setMemberCString(this, memberName, str);
            })
          });
          Object.assign(StructType.prototype, {
            addOnDispose: function (...v) {
              __addOnDispose(this, ...v);
              return this;
            }
          });
          Object.defineProperties(StructType, {
            allocCString: rop(__allocCString),
            isA: rop(v => v instanceof StructType),
            hasExternalPointer: rop(v => {
              const ii = getInstanceHandle(v, false);
              return !!(ii?.p && !ii?.ownsPointer);
            }),
            memberKey: __memberKeyProp
          });
          const memberGetterProxy = function (si) {
            return si.get || (si.adaptGet ? StructBinder.adaptGet(si.adaptGet) : void 0);
          };
          const memberSetterProxy = function (si) {
            return si.set || (si.adaptSet ? StructBinder.adaptSet(si.adaptSet) : void 0);
          };
          const makeMemberStructWrapper = function callee(ctor, name, si) {
            const __innerStructs = callee.innerStructs ??= /* @__PURE__ */new Map();
            const key = ctor.memberKey(name);
            if (void 0 !== si.signature) toss("'signature' cannot be used on an embedded struct (", ctor.structName, ".", key, ").");
            if (memberSetterProxy(si)) toss("'set' and 'adaptSet' are not permitted for nested struct members.");
            si.structName ??= ctor.structName + "::" + name;
            si.key = key;
            si.name = name;
            si.constructor = this.call(this, si.structName, si);
            const getterProxy = memberGetterProxy(si);
            const prop = Object.assign(Object.create(null), {
              configurable: false,
              enumerable: false,
              set: __propThrowOnSet(ctor.structName, key),
              get: function () {
                const dbg = this.debugFlags.__flags;
                const p = this.pointer;
                const k = p + "." + key;
                let s = __innerStructs.get(k);
                if (dbg.getter) log("debug.getter: k =", k);
                if (!s) {
                  s = new si.constructor(__ptrAdd(p, si.offset));
                  __innerStructs.set(k, s);
                  this.addOnDispose(() => s.dispose());
                  s.addOnDispose(() => __innerStructs.delete(k));
                }
                if (getterProxy) s = getterProxy.apply(this, [s, key]);
                if (dbg.getter) log("debug.getter: result =", s);
                return s;
              }
            });
            Object.defineProperty(ctor.prototype, key, prop);
          };
          const makeMemberWrapper = function f(ctor, name, si) {
            si = __adaptStruct2(this, si);
            if (si.members) return makeMemberStructWrapper.call(this, ctor, name, si);
            if (!f.cache) {
              f.cache = {
                getters: {},
                setters: {},
                sw: {}
              };
              const a = ["i", "c", "C", "p", "P", "s", "f", "d", "v()"];
              if (bigIntEnabled) a.push("j");
              a.forEach(function (v) {
                f.cache.getters[v] = sigDVGetter(v);
                f.cache.setters[v] = sigDVSetter(v);
                f.cache.sw[v] = sigDVSetWrapper(v);
              });
              f.sigCheck = function (obj, name, key, sig) {
                if (Object.prototype.hasOwnProperty.call(obj, key)) toss(obj.structName, "already has a property named", key + ".");
                looksLikeASig(sig) || toss("Malformed signature for", sPropName(obj.structName, name) + ":", sig);
              };
            }
            const key = ctor.memberKey(name);
            f.sigCheck(ctor.prototype, name, key, si.signature);
            si.key = key;
            si.name = name;
            const sigGlyph = sigLetter(si.signature);
            const xPropName = sPropName(ctor.structName, key);
            const dbg = ctor.debugFlags.__flags;
            const getterProxy = memberGetterProxy(si);
            const prop = Object.create(null);
            prop.configurable = false;
            prop.enumerable = false;
            prop.get = function () {
              if (dbg.getter) log("debug.getter:", f.cache.getters[sigGlyph], "for", sigIR(sigGlyph), xPropName, "@", this.pointer, "+", si.offset, "sz", si.sizeof);
              let rc = new DataView(heap().buffer, Number(this.pointer) + si.offset, si.sizeof)[f.cache.getters[sigGlyph]](0, isLittleEndian);
              if (getterProxy) rc = getterProxy.apply(this, [key, rc]);
              if (dbg.getter) log("debug.getter:", xPropName, "result =", rc);
              return rc;
            };
            if (si.readOnly) prop.set = __propThrowOnSet(ctor.prototype.structName, key);else {
              const setterProxy = memberSetterProxy(si);
              prop.set = function (v) {
                if (dbg.setter) log("debug.setter:", f.cache.setters[sigGlyph], "for", sigIR(sigGlyph), xPropName, "@", this.pointer, "+", si.offset, "sz", si.sizeof, v);
                if (!this.pointer) toss("Cannot set native property on a disposed", this.structName, "instance.");
                if (setterProxy) v = setterProxy.apply(this, [key, v]);
                if (null === v || void 0 === v) v = __NullPtr;else if (isPtrSig(si.signature) && !__isPtr(v)) if (isAutoPtrSig(si.signature) && v instanceof StructType) {
                  v = v.pointer || __NullPtr;
                  if (dbg.setter) log("debug.setter:", xPropName, "resolved to", v);
                } else toss("Invalid value for pointer-type", xPropName + ".");
                new DataView(heap().buffer, Number(this.pointer) + si.offset, si.sizeof)[f.cache.setters[sigGlyph]](0, f.cache.sw[sigGlyph](v), isLittleEndian);
              };
            }
            Object.defineProperty(ctor.prototype, key, prop);
          };
          const StructBinderImpl = function StructBinderImpl(structName, si, opt = Object.create(null)) {
            const StructCtor = function StructCtor(arg) {
              if (!(this instanceof StructCtor)) toss("The", structName, "constructor may only be called via 'new'.");
              __allocStruct(StructCtor, this, ...arguments);
            };
            const self = this;
            const ads = x => {
              return "string" === typeof x && looksLikeASig(x) ? {
                signature: x
              } : __adaptStruct2(self, x);
            };
            if (1 === arguments.length) {
              si = ads(structName);
              structName = si.structName || si.name;
            } else if (2 === arguments.length) {
              si = ads(si);
              si.name ??= structName;
            } else si = ads(si);
            structName ??= si.structName;
            structName ??= opt.structName;
            if (!structName) toss("One of 'name' or 'structName' are required.");
            if (si.adapt) {
              Object.keys(si.adapt.struct || {}).forEach(k => {
                __adaptStruct.call(StructBinderImpl, k, si.adapt.struct[k]);
              });
              Object.keys(si.adapt.set || {}).forEach(k => {
                __adaptSet.call(StructBinderImpl, k, si.adapt.set[k]);
              });
              Object.keys(si.adapt.get || {}).forEach(k => {
                __adaptGet.call(StructBinderImpl, k, si.adapt.get[k]);
              });
            }
            if (!si.members && !si.sizeof) si.sizeof = sigSize(si.signature);
            const debugFlags = rop(SBF.__makeDebugFlags(StructBinder.debugFlags));
            Object.defineProperties(StructCtor, {
              debugFlags,
              isA: rop(v => v instanceof StructCtor),
              memberKey: __memberKeyProp,
              memberKeys: __structMemberKeys,
              structInfo: rop(si),
              structName: rop(structName),
              ptrAdd: rop(__ptrAdd)
            });
            StructCtor.prototype = new StructType(structName, si, rop);
            Object.defineProperties(StructCtor.prototype, {
              debugFlags,
              constructor: rop(StructCtor),
              ptrAdd: rop(__ptrAddSelf)
            });
            let lastMember = false;
            let offset = 0;
            const autoCalc = !!si.autoCalcSizeOffset;
            if (!autoCalc) {
              if (!si.sizeof) toss(structName, "description is missing its sizeof property.");
              si.offset ??= 0;
            } else si.offset ??= 0;
            Object.keys(si.members || {}).forEach(k => {
              let m = ads(si.members[k]);
              if (!m.members && !m.sizeof) {
                m.sizeof = sigSize(m.signature);
                if (!m.sizeof) toss(sPropName(structName, k), "is missing a sizeof property.", m);
              }
              if (void 0 === m.offset) if (autoCalc) m.offset = offset;else toss(sPropName(structName, k), "is missing its offset.", JSON.stringify(m));
              si.members[k] = m;
              if (!lastMember || lastMember.offset < m.offset) lastMember = m;
              const oldAutoCalc = !!m.autoCalc;
              if (autoCalc) m.autoCalcSizeOffset = true;
              makeMemberWrapper.call(self, StructCtor, k, m);
              if (oldAutoCalc) m.autoCalcSizeOffset = true;else delete m.autoCalcSizeOffset;
              offset += m.sizeof;
            });
            if (!lastMember) toss("No member property descriptions found.");
            if (!si.sizeof) si.sizeof = offset;
            if (si.sizeof === 1) si.signature === "c" || si.signature === "C" || toss("Unexpected sizeof==1 member", sPropName(structName, k), "with signature", si.signature);else {
              if (0 !== si.sizeof % 4) {
                console.warn("Invalid struct member description", si);
                toss(structName, "sizeof is not aligned. sizeof=" + si.sizeof);
              }
              if (0 !== si.offset % 4) {
                console.warn("Invalid struct member description", si);
                toss(structName, "offset is not aligned. offset=" + si.offset);
              }
            }
            if (si.sizeof < offset) {
              console.warn("Suspect struct description:", si, "offset =", offset);
              toss("Mismatch in the calculated vs. the provided sizeof/offset info.", "Expected sizeof", offset, "but got", si.sizeof, "for", si);
            }
            delete si.autoCalcSizeOffset;
            return StructCtor;
          };
          const StructBinder = function StructBinder(structName, structInfo) {
            return 1 == arguments.length ? StructBinderImpl.call(StructBinder, structName) : StructBinderImpl.call(StructBinder, structName, structInfo);
          };
          StructBinder.StructType = StructType;
          StructBinder.config = config;
          StructBinder.allocCString = __allocCString;
          StructBinder.adaptGet = __adaptGet;
          StructBinder.adaptSet = __adaptSet;
          StructBinder.adaptStruct = __adaptStruct;
          StructBinder.ptrAdd = __ptrAdd;
          if (!StructBinder.debugFlags) StructBinder.debugFlags = SBF.__makeDebugFlags(SBF.debugFlags);
          return StructBinder;
        };
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {

          const toss = (...args) => {
            throw new Error(args.join(" "));
          };
          const capi = sqlite3.capi,
            wasm = sqlite3.wasm,
            util = sqlite3.util;
          globalThis.WhWasmUtilInstaller(wasm);
          delete globalThis.WhWasmUtilInstaller;
          const bindingSignatures = {
            core: [["sqlite3_aggregate_context", "void*", "sqlite3_context*", "int"], ["sqlite3_bind_double", "int", "sqlite3_stmt*", "int", "f64"], ["sqlite3_bind_int", "int", "sqlite3_stmt*", "int", "int"], ["sqlite3_bind_null", void 0, "sqlite3_stmt*", "int"], ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"], ["sqlite3_bind_parameter_index", "int", "sqlite3_stmt*", "string"], ["sqlite3_bind_parameter_name", "string", "sqlite3_stmt*", "int"], ["sqlite3_bind_pointer", "int", "sqlite3_stmt*", "int", "*", "string:static", "*"], ["sqlite3_busy_handler", "int", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
              signature: "i(pi)",
              contextKey: (argv, argIndex) => argv[0]
            }), "*"]], ["sqlite3_busy_timeout", "int", "sqlite3*", "int"], ["sqlite3_changes", "int", "sqlite3*"], ["sqlite3_clear_bindings", "int", "sqlite3_stmt*"], ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"], ["sqlite3_column_blob", "*", "sqlite3_stmt*", "int"], ["sqlite3_column_bytes", "int", "sqlite3_stmt*", "int"], ["sqlite3_column_count", "int", "sqlite3_stmt*"], ["sqlite3_column_decltype", "string", "sqlite3_stmt*", "int"], ["sqlite3_column_double", "f64", "sqlite3_stmt*", "int"], ["sqlite3_column_int", "int", "sqlite3_stmt*", "int"], ["sqlite3_column_name", "string", "sqlite3_stmt*", "int"], ["sqlite3_column_type", "int", "sqlite3_stmt*", "int"], ["sqlite3_column_value", "sqlite3_value*", "sqlite3_stmt*", "int"], ["sqlite3_commit_hook", "void*", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
              name: "sqlite3_commit_hook",
              signature: "i(p)",
              contextKey: argv => argv[0]
            }), "*"]], ["sqlite3_compileoption_get", "string", "int"], ["sqlite3_compileoption_used", "int", "string"], ["sqlite3_complete", "int", "string:flexible"], ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"], ["sqlite3_data_count", "int", "sqlite3_stmt*"], ["sqlite3_db_filename", "string", "sqlite3*", "string"], ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"], ["sqlite3_db_name", "string", "sqlite3*", "int"], ["sqlite3_db_readonly", "int", "sqlite3*", "string"], ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"], ["sqlite3_errcode", "int", "sqlite3*"], ["sqlite3_errmsg", "string", "sqlite3*"], ["sqlite3_error_offset", "int", "sqlite3*"], ["sqlite3_errstr", "string", "int"], ["sqlite3_exec", "int", ["sqlite3*", "string:flexible", new wasm.xWrap.FuncPtrAdapter({
              signature: "i(pipp)",
              bindScope: "transient",
              callProxy: callback => {
                let aNames;
                return (pVoid, nCols, pColVals, pColNames) => {
                  try {
                    const aVals = wasm.cArgvToJs(nCols, pColVals);
                    if (!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
                    return callback(aVals, aNames) | 0;
                  } catch (e) {
                    return e.resultCode || capi.SQLITE_ERROR;
                  }
                };
              }
            }), "*", "**"]], ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"], ["sqlite3_extended_errcode", "int", "sqlite3*"], ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"], ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"], ["sqlite3_finalize", "int", "sqlite3_stmt*"], ["sqlite3_free", void 0, "*"], ["sqlite3_get_autocommit", "int", "sqlite3*"], ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"], ["sqlite3_initialize", void 0], ["sqlite3_interrupt", void 0, "sqlite3*"], ["sqlite3_is_interrupted", "int", "sqlite3*"], ["sqlite3_keyword_count", "int"], ["sqlite3_keyword_name", "int", ["int", "**", "*"]], ["sqlite3_keyword_check", "int", ["string", "int"]], ["sqlite3_libversion", "string"], ["sqlite3_libversion_number", "int"], ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]], ["sqlite3_malloc", "*", "int"], ["sqlite3_next_stmt", "sqlite3_stmt*", ["sqlite3*", "sqlite3_stmt*"]], ["sqlite3_open", "int", "string", "*"], ["sqlite3_open_v2", "int", "string", "*", "int", "string"], ["sqlite3_realloc", "*", "*", "int"], ["sqlite3_reset", "int", "sqlite3_stmt*"], ["sqlite3_result_blob", void 0, "sqlite3_context*", "*", "int", "*"], ["sqlite3_result_double", void 0, "sqlite3_context*", "f64"], ["sqlite3_result_error", void 0, "sqlite3_context*", "string", "int"], ["sqlite3_result_error_code", void 0, "sqlite3_context*", "int"], ["sqlite3_result_error_nomem", void 0, "sqlite3_context*"], ["sqlite3_result_error_toobig", void 0, "sqlite3_context*"], ["sqlite3_result_int", void 0, "sqlite3_context*", "int"], ["sqlite3_result_null", void 0, "sqlite3_context*"], ["sqlite3_result_pointer", void 0, "sqlite3_context*", "*", "string:static", "*"], ["sqlite3_result_subtype", void 0, "sqlite3_value*", "int"], ["sqlite3_result_text", void 0, "sqlite3_context*", "string", "int", "*"], ["sqlite3_result_zeroblob", void 0, "sqlite3_context*", "int"], ["sqlite3_rollback_hook", "void*", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
              name: "sqlite3_rollback_hook",
              signature: "v(p)",
              contextKey: argv => argv[0]
            }), "*"]], ["sqlite3_set_auxdata", void 0, ["sqlite3_context*", "int", "*", "*"]], ["sqlite3_set_errmsg", "int", "sqlite3*", "int", "string"], ["sqlite3_shutdown", void 0], ["sqlite3_sourceid", "string"], ["sqlite3_sql", "string", "sqlite3_stmt*"], ["sqlite3_status", "int", "int", "*", "*", "int"], ["sqlite3_step", "int", "sqlite3_stmt*"], ["sqlite3_stmt_busy", "int", "sqlite3_stmt*"], ["sqlite3_stmt_readonly", "int", "sqlite3_stmt*"], ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"], ["sqlite3_strglob", "int", "string", "string"], ["sqlite3_stricmp", "int", "string", "string"], ["sqlite3_strlike", "int", "string", "string", "int"], ["sqlite3_strnicmp", "int", "string", "string", "int"], ["sqlite3_table_column_metadata", "int", "sqlite3*", "string", "string", "string", "**", "**", "*", "*", "*"], ["sqlite3_total_changes", "int", "sqlite3*"], ["sqlite3_trace_v2", "int", ["sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
              name: "sqlite3_trace_v2::callback",
              signature: "i(ippp)",
              contextKey: (argv, argIndex) => argv[0]
            }), "*"]], ["sqlite3_txn_state", "int", ["sqlite3*", "string"]], ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], ["sqlite3_uri_key", "string", "sqlite3_filename", "int"], ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], ["sqlite3_user_data", "void*", "sqlite3_context*"], ["sqlite3_value_blob", "*", "sqlite3_value*"], ["sqlite3_value_bytes", "int", "sqlite3_value*"], ["sqlite3_value_double", "f64", "sqlite3_value*"], ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"], ["sqlite3_value_free", void 0, "sqlite3_value*"], ["sqlite3_value_frombind", "int", "sqlite3_value*"], ["sqlite3_value_int", "int", "sqlite3_value*"], ["sqlite3_value_nochange", "int", "sqlite3_value*"], ["sqlite3_value_numeric_type", "int", "sqlite3_value*"], ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], ["sqlite3_value_subtype", "int", "sqlite3_value*"], ["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_vfs_find", "*", "string"], ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]],
            int64: [["sqlite3_bind_int64", "int", ["sqlite3_stmt*", "int", "i64"]], ["sqlite3_changes64", "i64", ["sqlite3*"]], ["sqlite3_column_int64", "i64", ["sqlite3_stmt*", "int"]], ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"], ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]], ["sqlite3_malloc64", "*", "i64"], ["sqlite3_msize", "i64", "*"], ["sqlite3_overload_function", "int", ["sqlite3*", "string", "int"]], ["sqlite3_realloc64", "*", "*", "i64"], ["sqlite3_result_int64", void 0, "*", "i64"], ["sqlite3_result_zeroblob64", "int", "*", "i64"], ["sqlite3_serialize", "*", "sqlite3*", "string", "*", "int"], ["sqlite3_set_last_insert_rowid", void 0, ["sqlite3*", "i64"]], ["sqlite3_status64", "int", "int", "*", "*", "int"], ["sqlite3_db_status64", "int", "sqlite3*", "int", "*", "*", "int"], ["sqlite3_total_changes64", "i64", ["sqlite3*"]], ["sqlite3_update_hook", "*", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
              name: "sqlite3_update_hook::callback",
              signature: "v(pippj)",
              contextKey: argv => argv[0],
              callProxy: callback => {
                return (p, op, z0, z1, rowid) => {
                  callback(p, op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), rowid);
                };
              }
            }), "*"]], ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]], ["sqlite3_value_int64", "i64", "sqlite3_value*"]],
            wasmInternal: [["sqlite3__wasm_db_reset", "int", "sqlite3*"], ["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*", "string"], ["sqlite3__wasm_vfs_create_file", "int", "sqlite3_vfs*", "string", "*", "int"], ["sqlite3__wasm_posix_create_file", "int", "string", "*", "int"], ["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*", "string"], ["sqlite3__wasm_qfmt_token", "string:dealloc", "string", "int"]]
          };
          if (!!wasm.exports.sqlite3_progress_handler) bindingSignatures.core.push(["sqlite3_progress_handler", void 0, ["sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
            name: "xProgressHandler",
            signature: "i(p)",
            bindScope: "context",
            contextKey: (argv, argIndex) => argv[0]
          }), "*"]]);
          if (!!wasm.exports.sqlite3_stmt_explain) bindingSignatures.core.push(["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"], ["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"]);
          if (!!wasm.exports.sqlite3_set_authorizer) bindingSignatures.core.push(["sqlite3_set_authorizer", "int", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
            name: "sqlite3_set_authorizer::xAuth",
            signature: "i(pissss)",
            contextKey: (argv, argIndex) => argv[0],
            callProxy: callback => {
              return (pV, iCode, s0, s1, s2, s3) => {
                try {
                  s0 = s0 && wasm.cstrToJs(s0);
                  s1 = s1 && wasm.cstrToJs(s1);
                  s2 = s2 && wasm.cstrToJs(s2);
                  s3 = s3 && wasm.cstrToJs(s3);
                  return callback(pV, iCode, s0, s1, s2, s3) | 0;
                } catch (e) {
                  return e.resultCode || capi.SQLITE_ERROR;
                }
              };
            }
          }), "*"]]);
          if (!!wasm.exports.sqlite3_column_origin_name) bindingSignatures.core.push(["sqlite3_column_database_name", "string", "sqlite3_stmt*", "int"], ["sqlite3_column_origin_name", "string", "sqlite3_stmt*", "int"], ["sqlite3_column_table_name", "string", "sqlite3_stmt*", "int"]);
          if (wasm.bigIntEnabled && !!wasm.exports.sqlite3_declare_vtab) bindingSignatures.int64.push(["sqlite3_create_module", "int", ["sqlite3*", "string", "sqlite3_module*", "*"]], ["sqlite3_create_module_v2", "int", ["sqlite3*", "string", "sqlite3_module*", "*", "*"]], ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]], ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]], ["sqlite3_vtab_collation", "string", "sqlite3_index_info*", "int"], ["sqlite3_vtab_distinct", "int", "sqlite3_index_info*"], ["sqlite3_vtab_in", "int", "sqlite3_index_info*", "int", "int"], ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"], ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"], ["sqlite3_vtab_nochange", "int", "sqlite3_context*"], ["sqlite3_vtab_on_conflict", "int", "sqlite3*"], ["sqlite3_vtab_rhs_value", "int", "sqlite3_index_info*", "int", "**"]);
          if (wasm.bigIntEnabled && !!wasm.exports.sqlite3_preupdate_hook) bindingSignatures.int64.push(["sqlite3_preupdate_blobwrite", "int", "sqlite3*"], ["sqlite3_preupdate_count", "int", "sqlite3*"], ["sqlite3_preupdate_depth", "int", "sqlite3*"], ["sqlite3_preupdate_hook", "*", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
            name: "sqlite3_preupdate_hook",
            signature: "v(ppippjj)",
            contextKey: argv => argv[0],
            callProxy: callback => {
              return (p, db, op, zDb, zTbl, iKey1, iKey2) => {
                callback(p, db, op, wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl), iKey1, iKey2);
              };
            }
          }), "*"]], ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]], ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]]);
          if (wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add && !!wasm.exports.sqlite3session_create && !!wasm.exports.sqlite3_preupdate_hook) {
            const __ipsProxy = {
              signature: "i(ps)",
              callProxy: callback => {
                return (p, s) => {
                  try {
                    return callback(p, wasm.cstrToJs(s)) | 0;
                  } catch (e) {
                    return e.resultCode || capi.SQLITE_ERROR;
                  }
                };
              }
            };
            bindingSignatures.int64.push(["sqlite3changegroup_add", "int", ["sqlite3_changegroup*", "int", "void*"]], ["sqlite3changegroup_add_strm", "int", ["sqlite3_changegroup*", new wasm.xWrap.FuncPtrAdapter({
              name: "xInput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3changegroup_delete", void 0, ["sqlite3_changegroup*"]], ["sqlite3changegroup_new", "int", ["**"]], ["sqlite3changegroup_output", "int", ["sqlite3_changegroup*", "int*", "**"]], ["sqlite3changegroup_output_strm", "int", ["sqlite3_changegroup*", new wasm.xWrap.FuncPtrAdapter({
              name: "xOutput",
              signature: "i(ppi)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3changeset_apply", "int", ["sqlite3*", "int", "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xFilter",
              bindScope: "transient",
              ...__ipsProxy
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xConflict",
              signature: "i(pip)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3changeset_apply_strm", "int", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
              name: "xInput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xFilter",
              bindScope: "transient",
              ...__ipsProxy
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xConflict",
              signature: "i(pip)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3changeset_apply_v2", "int", ["sqlite3*", "int", "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xFilter",
              bindScope: "transient",
              ...__ipsProxy
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xConflict",
              signature: "i(pip)",
              bindScope: "transient"
            }), "void*", "**", "int*", "int"]], ["sqlite3changeset_apply_v2_strm", "int", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
              name: "xInput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xFilter",
              bindScope: "transient",
              ...__ipsProxy
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xConflict",
              signature: "i(pip)",
              bindScope: "transient"
            }), "void*", "**", "int*", "int"]], ["sqlite3changeset_apply_v3", "int", ["sqlite3*", "int", "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xFilter",
              signature: "i(pp)",
              bindScope: "transient"
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xConflict",
              signature: "i(pip)",
              bindScope: "transient"
            }), "void*", "**", "int*", "int"]], ["sqlite3changeset_apply_v3_strm", "int", ["sqlite3*", new wasm.xWrap.FuncPtrAdapter({
              name: "xInput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xFilter",
              signature: "i(pp)",
              bindScope: "transient"
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xConflict",
              signature: "i(pip)",
              bindScope: "transient"
            }), "void*", "**", "int*", "int"]], ["sqlite3changeset_concat", "int", ["int", "void*", "int", "void*", "int*", "**"]], ["sqlite3changeset_concat_strm", "int", [new wasm.xWrap.FuncPtrAdapter({
              name: "xInputA",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xInputB",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xOutput",
              signature: "i(ppi)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3changeset_conflict", "int", ["sqlite3_changeset_iter*", "int", "**"]], ["sqlite3changeset_finalize", "int", ["sqlite3_changeset_iter*"]], ["sqlite3changeset_fk_conflicts", "int", ["sqlite3_changeset_iter*", "int*"]], ["sqlite3changeset_invert", "int", ["int", "void*", "int*", "**"]], ["sqlite3changeset_invert_strm", "int", [new wasm.xWrap.FuncPtrAdapter({
              name: "xInput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*", new wasm.xWrap.FuncPtrAdapter({
              name: "xOutput",
              signature: "i(ppi)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3changeset_new", "int", ["sqlite3_changeset_iter*", "int", "**"]], ["sqlite3changeset_next", "int", ["sqlite3_changeset_iter*"]], ["sqlite3changeset_old", "int", ["sqlite3_changeset_iter*", "int", "**"]], ["sqlite3changeset_op", "int", ["sqlite3_changeset_iter*", "**", "int*", "int*", "int*"]], ["sqlite3changeset_pk", "int", ["sqlite3_changeset_iter*", "**", "int*"]], ["sqlite3changeset_start", "int", ["**", "int", "*"]], ["sqlite3changeset_start_strm", "int", ["**", new wasm.xWrap.FuncPtrAdapter({
              name: "xInput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3changeset_start_v2", "int", ["**", "int", "*", "int"]], ["sqlite3changeset_start_v2_strm", "int", ["**", new wasm.xWrap.FuncPtrAdapter({
              name: "xInput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*", "int"]], ["sqlite3session_attach", "int", ["sqlite3_session*", "string"]], ["sqlite3session_changeset", "int", ["sqlite3_session*", "int*", "**"]], ["sqlite3session_changeset_size", "i64", ["sqlite3_session*"]], ["sqlite3session_changeset_strm", "int", ["sqlite3_session*", new wasm.xWrap.FuncPtrAdapter({
              name: "xOutput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3session_config", "int", ["int", "void*"]], ["sqlite3session_create", "int", ["sqlite3*", "string", "**"]], ["sqlite3session_diff", "int", ["sqlite3_session*", "string", "string", "**"]], ["sqlite3session_enable", "int", ["sqlite3_session*", "int"]], ["sqlite3session_indirect", "int", ["sqlite3_session*", "int"]], ["sqlite3session_isempty", "int", ["sqlite3_session*"]], ["sqlite3session_memory_used", "i64", ["sqlite3_session*"]], ["sqlite3session_object_config", "int", ["sqlite3_session*", "int", "void*"]], ["sqlite3session_patchset", "int", ["sqlite3_session*", "*", "**"]], ["sqlite3session_patchset_strm", "int", ["sqlite3_session*", new wasm.xWrap.FuncPtrAdapter({
              name: "xOutput",
              signature: "i(ppp)",
              bindScope: "transient"
            }), "void*"]], ["sqlite3session_table_filter", void 0, ["sqlite3_session*", new wasm.xWrap.FuncPtrAdapter({
              name: "xFilter",
              ...__ipsProxy,
              contextKey: (argv, argIndex) => argv[0]
            }), "*"]]);
          }
          sqlite3.StructBinder = globalThis.Jaccwabyt({
            heap: wasm.heap8u,
            alloc: wasm.alloc,
            dealloc: wasm.dealloc,
            bigIntEnabled: wasm.bigIntEnabled,
            pointerIR: wasm.ptr.ir,
            memberPrefix: "$"
          });
          delete globalThis.Jaccwabyt;
          {
            const __xString = wasm.xWrap.argAdapter("string");
            wasm.xWrap.argAdapter("string:flexible", v => __xString(util.flexibleString(v)));
            wasm.xWrap.argAdapter("string:static", function (v) {
              if (wasm.isPtr(v)) return v;
              v = "" + v;
              return this[v] || (this[v] = wasm.allocCString(v));
            }.bind(Object.create(null)));
            const __xArgPtr = wasm.xWrap.argAdapter("*");
            const nilType = function () {};
            wasm.xWrap.argAdapter("sqlite3_filename", __xArgPtr)("sqlite3_context*", __xArgPtr)("sqlite3_value*", __xArgPtr)("void*", __xArgPtr)("sqlite3_changegroup*", __xArgPtr)("sqlite3_changeset_iter*", __xArgPtr)("sqlite3_session*", __xArgPtr)("sqlite3_stmt*", v => __xArgPtr(v instanceof (sqlite3?.oo1?.Stmt || nilType) ? v.pointer : v))("sqlite3*", v => __xArgPtr(v instanceof (sqlite3?.oo1?.DB || nilType) ? v.pointer : v))("sqlite3_vfs*", v => {
              if ("string" === typeof v) return capi.sqlite3_vfs_find(v) || sqlite3.SQLite3Error.toss(capi.SQLITE_NOTFOUND, "Unknown sqlite3_vfs name:", v);
              return __xArgPtr(v instanceof (capi.sqlite3_vfs || nilType) ? v.pointer : v);
            });
            if (wasm.exports.sqlite3_declare_vtab) wasm.xWrap.argAdapter("sqlite3_index_info*", v => __xArgPtr(v instanceof (capi.sqlite3_index_info || nilType) ? v.pointer : v))("sqlite3_module*", v => __xArgPtr(v instanceof (capi.sqlite3_module || nilType) ? v.pointer : v));
            const __xRcPtr = wasm.xWrap.resultAdapter("*");
            wasm.xWrap.resultAdapter("sqlite3*", __xRcPtr)("sqlite3_context*", __xRcPtr)("sqlite3_stmt*", __xRcPtr)("sqlite3_value*", __xRcPtr)("sqlite3_vfs*", __xRcPtr)("void*", __xRcPtr);
            for (const e of bindingSignatures.core) capi[e[0]] = wasm.xWrap.apply(null, e);
            for (const e of bindingSignatures.wasmInternal) util[e[0]] = wasm.xWrap.apply(null, e);
            for (const e of bindingSignatures.int64) capi[e[0]] = wasm.bigIntEnabled ? wasm.xWrap.apply(null, e) : () => toss(e[0] + "() is unavailable due to lack", "of BigInt support in this build.");
            delete bindingSignatures.core;
            delete bindingSignatures.int64;
            delete bindingSignatures.wasmInternal;
            util.sqlite3__wasm_db_error = function (pDb, resultCode, message) {
              if (!pDb) return capi.SQLITE_MISUSE;
              if (resultCode instanceof sqlite3.WasmAllocError) {
                resultCode = capi.SQLITE_NOMEM;
                message = 0;
              } else if (resultCode instanceof Error) {
                message = message || "" + resultCode;
                resultCode = resultCode.resultCode || capi.SQLITE_ERROR;
              }
              return capi.sqlite3_set_errmsg(pDb, resultCode, message) || resultCode;
            };
          }
          {
            const cJson = wasm.xCall("sqlite3__wasm_enum_json");
            if (!cJson) toss("Maintenance required: increase sqlite3__wasm_enum_json()'s", "static buffer size!");
            wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
            const defineGroups = ["access", "authorizer", "blobFinalizers", "changeset", "config", "dataTypes", "dbConfig", "dbStatus", "encodings", "fcntl", "flock", "ioCap", "limits", "openFlags", "prepareFlags", "resultCodes", "sqlite3Status", "stmtStatus", "syncFlags", "trace", "txnState", "udfFlags", "version"];
            if (wasm.bigIntEnabled) defineGroups.push("serialize", "session", "vtab");
            for (const t of defineGroups) for (const e of Object.entries(wasm.ctype[t])) capi[e[0]] = e[1];
            if (!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)) toss("Internal error: cannot resolve exported function", "entry SQLITE_WASM_DEALLOC (==" + capi.SQLITE_WASM_DEALLOC + ").");
            const __rcMap = Object.create(null);
            for (const e of Object.entries(wasm.ctype["resultCodes"])) __rcMap[e[1]] = e[0];
            capi.sqlite3_js_rc_str = rc => __rcMap[rc];
            const notThese = Object.assign(Object.create(null), {
              WasmTestStruct: true,
              sqlite3_index_info: !wasm.bigIntEnabled,
              sqlite3_index_constraint: !wasm.bigIntEnabled,
              sqlite3_index_orderby: !wasm.bigIntEnabled,
              sqlite3_index_constraint_usage: !wasm.bigIntEnabled
            });
            for (const s of wasm.ctype.structs) if (!notThese[s.name]) capi[s.name] = sqlite3.StructBinder(s);
            if (capi.sqlite3_index_info) {
              for (const k of ["sqlite3_index_constraint", "sqlite3_index_orderby", "sqlite3_index_constraint_usage"]) {
                capi.sqlite3_index_info[k] = capi[k];
                delete capi[k];
              }
              capi.sqlite3_vtab_config = wasm.xWrap("sqlite3__wasm_vtab_config", "int", ["sqlite3*", "int", "int"]);
            }
          }
          const __dbArgcMismatch = (pDb, f, n) => {
            return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE, f + "() requires " + n + " argument" + (1 === n ? "" : "s") + ".");
          };
          const __errEncoding = pDb => {
            return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding.");
          };
          const __argPDb = pDb => wasm.xWrap.argAdapter("sqlite3*")(pDb);
          const __argStr = str => wasm.isPtr(str) ? wasm.cstrToJs(str) : str;
          const __dbCleanupMap = function (pDb, mode) {
            pDb = __argPDb(pDb);
            let m = this.dbMap.get(pDb);
            if (!mode) {
              this.dbMap.delete(pDb);
              return m;
            } else if (!m && mode > 0) this.dbMap.set(pDb, m = Object.create(null));
            return m;
          }.bind(Object.assign(Object.create(null), {
            dbMap: /* @__PURE__ */new Map()
          }));
          __dbCleanupMap.addCollation = function (pDb, name) {
            const m = __dbCleanupMap(pDb, 1);
            if (!m.collation) m.collation = /* @__PURE__ */new Set();
            m.collation.add(__argStr(name).toLowerCase());
          };
          __dbCleanupMap._addUDF = function (pDb, name, arity, map) {
            name = __argStr(name).toLowerCase();
            let u = map.get(name);
            if (!u) map.set(name, u = /* @__PURE__ */new Set());
            u.add(arity < 0 ? -1 : arity);
          };
          __dbCleanupMap.addFunction = function (pDb, name, arity) {
            const m = __dbCleanupMap(pDb, 1);
            if (!m.udf) m.udf = /* @__PURE__ */new Map();
            this._addUDF(pDb, name, arity, m.udf);
          };
          if (wasm.exports.sqlite3_create_window_function) __dbCleanupMap.addWindowFunc = function (pDb, name, arity) {
            const m = __dbCleanupMap(pDb, 1);
            if (!m.wudf) m.wudf = /* @__PURE__ */new Map();
            this._addUDF(pDb, name, arity, m.wudf);
          };
          __dbCleanupMap.cleanup = function (pDb) {
            pDb = __argPDb(pDb);
            for (const obj of [["sqlite3_busy_handler", 3], ["sqlite3_commit_hook", 3], ["sqlite3_preupdate_hook", 3], ["sqlite3_progress_handler", 4], ["sqlite3_rollback_hook", 3], ["sqlite3_set_authorizer", 3], ["sqlite3_trace_v2", 4], ["sqlite3_update_hook", 3]]) {
              const [name, arity] = obj;
              if (!wasm.exports[name]) continue;
              const closeArgs = [pDb];
              closeArgs.length = arity;
              try {
                capi[name](...closeArgs);
              } catch (e) {
                sqlite3.config.warn("close-time call of", name + "(", closeArgs, ") threw:", e);
              }
            }
            const m = __dbCleanupMap(pDb, 0);
            if (!m) return;
            if (m.collation) {
              for (const name of m.collation) try {
                capi.sqlite3_create_collation_v2(pDb, name, capi.SQLITE_UTF8, 0, 0, 0);
              } catch (e) {}
              delete m.collation;
            }
            let i;
            for (i = 0; i < 2; ++i) {
              const fmap = i ? m.wudf : m.udf;
              if (!fmap) continue;
              const func = i ? capi.sqlite3_create_window_function : capi.sqlite3_create_function_v2;
              for (const e of fmap) {
                const name = e[0],
                  arities = e[1];
                const fargs = [pDb, name, 0, capi.SQLITE_UTF8, 0, 0, 0, 0, 0];
                if (i) fargs.push(0);
                for (const arity of arities) try {
                  fargs[2] = arity;
                  func.apply(null, fargs);
                } catch (e) {}
                arities.clear();
              }
              fmap.clear();
            }
            delete m.udf;
            delete m.wudf;
          };
          {
            const __sqlite3CloseV2 = wasm.xWrap("sqlite3_close_v2", "int", "sqlite3*");
            capi.sqlite3_close_v2 = function (pDb) {
              if (1 !== arguments.length) return __dbArgcMismatch(pDb, "sqlite3_close_v2", 1);
              if (pDb) try {
                __dbCleanupMap.cleanup(pDb);
              } catch (e) {}
              return __sqlite3CloseV2(pDb);
            };
          }
          if (capi.sqlite3session_create) {
            const __sqlite3SessionDelete = wasm.xWrap("sqlite3session_delete", void 0, ["sqlite3_session*"]);
            capi.sqlite3session_delete = function (pSession) {
              if (1 !== arguments.length) return __dbArgcMismatch(pDb, "sqlite3session_delete", 1);else if (pSession) capi.sqlite3session_table_filter(pSession, 0, 0);
              __sqlite3SessionDelete(pSession);
            };
          }
          {
            const contextKey = (argv, argIndex) => {
              return "argv[" + argIndex + "]:" + argv[0] + ":" + wasm.cstrToJs(argv[1]).toLowerCase();
            };
            const __sqlite3CreateCollationV2 = wasm.xWrap("sqlite3_create_collation_v2", "int", ["sqlite3*", "string", "int", "*", new wasm.xWrap.FuncPtrAdapter({
              name: "xCompare",
              signature: "i(pipip)",
              contextKey
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xDestroy",
              signature: "v(p)",
              contextKey
            })]);
            capi.sqlite3_create_collation_v2 = function (pDb, zName, eTextRep, pArg, xCompare, xDestroy) {
              if (6 !== arguments.length) return __dbArgcMismatch(pDb, "sqlite3_create_collation_v2", 6);else if (0 === (eTextRep & 15)) eTextRep |= capi.SQLITE_UTF8;else if (capi.SQLITE_UTF8 !== (eTextRep & 15)) return __errEncoding(pDb);
              try {
                const rc = __sqlite3CreateCollationV2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
                if (0 === rc && xCompare instanceof Function) __dbCleanupMap.addCollation(pDb, zName);
                return rc;
              } catch (e) {
                return util.sqlite3__wasm_db_error(pDb, e);
              }
            };
            capi.sqlite3_create_collation = (pDb, zName, eTextRep, pArg, xCompare) => {
              return 5 === arguments.length ? capi.sqlite3_create_collation_v2(pDb, zName, eTextRep, pArg, xCompare, 0) : __dbArgcMismatch(pDb, "sqlite3_create_collation", 5);
            };
          }
          {
            const contextKey = function (argv, argIndex) {
              return argv[0] + ":" + (argv[2] < 0 ? -1 : argv[2]) + ":" + argIndex + ":" + wasm.cstrToJs(argv[1]).toLowerCase();
            };
            const __cfProxy = Object.assign(Object.create(null), {
              xInverseAndStep: {
                signature: "v(pip)",
                contextKey,
                callProxy: callback => {
                  return (pCtx, argc, pArgv) => {
                    try {
                      callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv));
                    } catch (e) {
                      capi.sqlite3_result_error_js(pCtx, e);
                    }
                  };
                }
              },
              xFinalAndValue: {
                signature: "v(p)",
                contextKey,
                callProxy: callback => {
                  return pCtx => {
                    try {
                      capi.sqlite3_result_js(pCtx, callback(pCtx));
                    } catch (e) {
                      capi.sqlite3_result_error_js(pCtx, e);
                    }
                  };
                }
              },
              xFunc: {
                signature: "v(pip)",
                contextKey,
                callProxy: callback => {
                  return (pCtx, argc, pArgv) => {
                    try {
                      capi.sqlite3_result_js(pCtx, callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)));
                    } catch (e) {
                      capi.sqlite3_result_error_js(pCtx, e);
                    }
                  };
                }
              },
              xDestroy: {
                signature: "v(p)",
                contextKey,
                callProxy: callback => {
                  return pVoid => {
                    try {
                      callback(pVoid);
                    } catch (e) {
                      console.error("UDF xDestroy method threw:", e);
                    }
                  };
                }
              }
            });
            const __sqlite3CreateFunction = wasm.xWrap("sqlite3_create_function_v2", "int", ["sqlite3*", "string", "int", "int", "*", new wasm.xWrap.FuncPtrAdapter({
              name: "xFunc",
              ...__cfProxy.xFunc
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xStep",
              ...__cfProxy.xInverseAndStep
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xFinal",
              ...__cfProxy.xFinalAndValue
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xDestroy",
              ...__cfProxy.xDestroy
            })]);
            const __sqlite3CreateWindowFunction = wasm.exports.sqlite3_create_window_function ? wasm.xWrap("sqlite3_create_window_function", "int", ["sqlite3*", "string", "int", "int", "*", new wasm.xWrap.FuncPtrAdapter({
              name: "xStep",
              ...__cfProxy.xInverseAndStep
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xFinal",
              ...__cfProxy.xFinalAndValue
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xValue",
              ...__cfProxy.xFinalAndValue
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xInverse",
              ...__cfProxy.xInverseAndStep
            }), new wasm.xWrap.FuncPtrAdapter({
              name: "xDestroy",
              ...__cfProxy.xDestroy
            })]) : void 0;
            capi.sqlite3_create_function_v2 = function f(pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal, xDestroy) {
              if (f.length !== arguments.length) return __dbArgcMismatch(pDb, "sqlite3_create_function_v2", f.length);else if (0 === (eTextRep & 15)) eTextRep |= capi.SQLITE_UTF8;else if (capi.SQLITE_UTF8 !== (eTextRep & 15)) return __errEncoding(pDb);
              try {
                const rc = __sqlite3CreateFunction(pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal, xDestroy);
                if (0 === rc && (xFunc instanceof Function || xStep instanceof Function || xFinal instanceof Function || xDestroy instanceof Function)) __dbCleanupMap.addFunction(pDb, funcName, nArg);
                return rc;
              } catch (e) {
                console.error("sqlite3_create_function_v2() setup threw:", e);
                return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: " + e);
              }
            };
            capi.sqlite3_create_function = function f(pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal) {
              return f.length === arguments.length ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep, pApp, xFunc, xStep, xFinal, 0) : __dbArgcMismatch(pDb, "sqlite3_create_function", f.length);
            };
            if (__sqlite3CreateWindowFunction) capi.sqlite3_create_window_function = function f(pDb, funcName, nArg, eTextRep, pApp, xStep, xFinal, xValue, xInverse, xDestroy) {
              if (f.length !== arguments.length) return __dbArgcMismatch(pDb, "sqlite3_create_window_function", f.length);else if (0 === (eTextRep & 15)) eTextRep |= capi.SQLITE_UTF8;else if (capi.SQLITE_UTF8 !== (eTextRep & 15)) return __errEncoding(pDb);
              try {
                const rc = __sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep, pApp, xStep, xFinal, xValue, xInverse, xDestroy);
                if (0 === rc && (xStep instanceof Function || xFinal instanceof Function || xValue instanceof Function || xInverse instanceof Function || xDestroy instanceof Function)) __dbCleanupMap.addWindowFunc(pDb, funcName, nArg);
                return rc;
              } catch (e) {
                console.error("sqlite3_create_window_function() setup threw:", e);
                return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: " + e);
              }
            };else delete capi.sqlite3_create_window_function;
            capi.sqlite3_create_function_v2.udfSetResult = capi.sqlite3_create_function.udfSetResult = capi.sqlite3_result_js;
            if (capi.sqlite3_create_window_function) capi.sqlite3_create_window_function.udfSetResult = capi.sqlite3_result_js;
            capi.sqlite3_create_function_v2.udfConvertArgs = capi.sqlite3_create_function.udfConvertArgs = capi.sqlite3_values_to_js;
            if (capi.sqlite3_create_window_function) capi.sqlite3_create_window_function.udfConvertArgs = capi.sqlite3_values_to_js;
            capi.sqlite3_create_function_v2.udfSetError = capi.sqlite3_create_function.udfSetError = capi.sqlite3_result_error_js;
            if (capi.sqlite3_create_window_function) capi.sqlite3_create_window_function.udfSetError = capi.sqlite3_result_error_js;
          }
          {
            const __flexiString = (v, n) => {
              if ("string" === typeof v) n = -1;else if (util.isSQLableTypedArray(v)) {
                n = v.byteLength;
                v = wasm.typedArrayToString(v instanceof ArrayBuffer ? new Uint8Array(v) : v);
              } else if (Array.isArray(v)) {
                v = v.join("");
                n = -1;
              }
              return [v, n];
            };
            const __prepare = {
              basic: wasm.xWrap("sqlite3_prepare_v3", "int", ["sqlite3*", "string", "int", "int", "**", "**"]),
              full: wasm.xWrap("sqlite3_prepare_v3", "int", ["sqlite3*", "*", "int", "int", "**", "**"])
            };
            capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail) {
              if (f.length !== arguments.length) return __dbArgcMismatch(pDb, "sqlite3_prepare_v3", f.length);
              const [xSql, xSqlLen] = __flexiString(sql, Number(sqlLen));
              switch (typeof xSql) {
                case "string":
                  return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null);
                case typeof wasm.ptr.null:
                  return __prepare.full(pDb, wasm.ptr.coerce(xSql), xSqlLen, prepFlags, ppStmt, pzTail);
                default:
                  return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE, "Invalid SQL argument type for sqlite3_prepare_v2/v3(). typeof=" + typeof xSql);
              }
            };
            capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail) {
              return f.length === arguments.length ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail) : __dbArgcMismatch(pDb, "sqlite3_prepare_v2", f.length);
            };
          }
          {
            const __bindText = wasm.xWrap("sqlite3_bind_text", "int", ["sqlite3_stmt*", "int", "string", "int", "*"]);
            const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", ["sqlite3_stmt*", "int", "*", "int", "*"]);
            capi.sqlite3_bind_text = function f(pStmt, iCol, text, nText, xDestroy) {
              if (f.length !== arguments.length) return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt), "sqlite3_bind_text", f.length);else if (wasm.isPtr(text) || null === text) return __bindText(pStmt, iCol, text, nText, xDestroy);else if (text instanceof ArrayBuffer) text = new Uint8Array(text);else if (Array.isArray(pMem)) text = pMem.join("");
              let p, n;
              try {
                if (util.isSQLableTypedArray(text)) {
                  p = wasm.allocFromTypedArray(text);
                  n = text.byteLength;
                } else if ("string" === typeof text) [p, n] = wasm.allocCString(text);else return util.sqlite3__wasm_db_error(capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE, "Invalid 3rd argument type for sqlite3_bind_text().");
                return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
              } catch (e) {
                wasm.dealloc(p);
                return util.sqlite3__wasm_db_error(capi.sqlite3_db_handle(pStmt), e);
              }
            };
            capi.sqlite3_bind_blob = function f(pStmt, iCol, pMem, nMem, xDestroy) {
              if (f.length !== arguments.length) return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt), "sqlite3_bind_blob", f.length);else if (wasm.isPtr(pMem) || null === pMem) return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy);else if (pMem instanceof ArrayBuffer) pMem = new Uint8Array(pMem);else if (Array.isArray(pMem)) pMem = pMem.join("");
              let p, n;
              try {
                if (util.isBindableTypedArray(pMem)) {
                  p = wasm.allocFromTypedArray(pMem);
                  n = nMem >= 0 ? nMem : pMem.byteLength;
                } else if ("string" === typeof pMem) [p, n] = wasm.allocCString(pMem);else return util.sqlite3__wasm_db_error(capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE, "Invalid 3rd argument type for sqlite3_bind_blob().");
                return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
              } catch (e) {
                wasm.dealloc(p);
                return util.sqlite3__wasm_db_error(capi.sqlite3_db_handle(pStmt), e);
              }
            };
          }
          if (!capi.sqlite3_column_text) {
            const argStmt = wasm.xWrap.argAdapter("sqlite3_stmt*"),
              argInt = wasm.xWrap.argAdapter("int"),
              argValue = wasm.xWrap.argAdapter("sqlite3_value*"),
              newStr = (cstr, n) => wasm.typedArrayToString(wasm.heap8u(), Number(cstr), Number(cstr) + n);
            capi.sqlite3_column_text = function (stmt, colIndex) {
              const a0 = argStmt(stmt),
                a1 = argInt(colIndex);
              const cstr = wasm.exports.sqlite3_column_text(a0, a1);
              return cstr ? newStr(cstr, wasm.exports.sqlite3_column_bytes(a0, a1)) : null;
            };
            capi.sqlite3_value_text = function (val) {
              const a0 = argValue(val);
              const cstr = wasm.exports.sqlite3_value_text(a0);
              return cstr ? newStr(cstr, wasm.exports.sqlite3_value_bytes(a0)) : null;
            };
          }
          capi.sqlite3_config = function (op, ...args) {
            if (arguments.length < 2) return capi.SQLITE_MISUSE;
            switch (op) {
              case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN:
              case capi.SQLITE_CONFIG_MEMSTATUS:
              case capi.SQLITE_CONFIG_SMALL_MALLOC:
              case capi.SQLITE_CONFIG_SORTERREF_SIZE:
              case capi.SQLITE_CONFIG_STMTJRNL_SPILL:
              case capi.SQLITE_CONFIG_URI:
                return wasm.exports.sqlite3__wasm_config_i(op, args[0]);
              case capi.SQLITE_CONFIG_LOOKASIDE:
                return wasm.exports.sqlite3__wasm_config_ii(op, args[0], args[1]);
              case capi.SQLITE_CONFIG_MEMDB_MAXSIZE:
                return wasm.exports.sqlite3__wasm_config_j(op, args[0]);
              case capi.SQLITE_CONFIG_GETMALLOC:
              case capi.SQLITE_CONFIG_GETMUTEX:
              case capi.SQLITE_CONFIG_GETPCACHE2:
              case capi.SQLITE_CONFIG_GETPCACHE:
              case capi.SQLITE_CONFIG_HEAP:
              case capi.SQLITE_CONFIG_LOG:
              case capi.SQLITE_CONFIG_MALLOC:
              case capi.SQLITE_CONFIG_MMAP_SIZE:
              case capi.SQLITE_CONFIG_MULTITHREAD:
              case capi.SQLITE_CONFIG_MUTEX:
              case capi.SQLITE_CONFIG_PAGECACHE:
              case capi.SQLITE_CONFIG_PCACHE2:
              case capi.SQLITE_CONFIG_PCACHE:
              case capi.SQLITE_CONFIG_PCACHE_HDRSZ:
              case capi.SQLITE_CONFIG_PMASZ:
              case capi.SQLITE_CONFIG_SERIALIZED:
              case capi.SQLITE_CONFIG_SINGLETHREAD:
              case capi.SQLITE_CONFIG_SQLLOG:
              case capi.SQLITE_CONFIG_WIN32_HEAPSIZE:
              default:
                return capi.SQLITE_NOTFOUND;
            }
          };
          {
            const __autoExtFptr = /* @__PURE__ */new Set();
            capi.sqlite3_auto_extension = function (fPtr) {
              if (fPtr instanceof Function) fPtr = wasm.installFunction("i(ppp)", fPtr);else if (1 !== arguments.length || !wasm.isPtr(fPtr)) return capi.SQLITE_MISUSE;
              const rc = wasm.exports.sqlite3_auto_extension(fPtr);
              if (fPtr !== arguments[0]) if (0 === rc) __autoExtFptr.add(fPtr);else wasm.uninstallFunction(fPtr);
              return rc;
            };
            capi.sqlite3_cancel_auto_extension = function (fPtr) {
              if (!fPtr || 1 !== arguments.length || !wasm.isPtr(fPtr)) return 0;
              return wasm.exports.sqlite3_cancel_auto_extension(fPtr);
            };
            capi.sqlite3_reset_auto_extension = function () {
              wasm.exports.sqlite3_reset_auto_extension();
              for (const fp of __autoExtFptr) wasm.uninstallFunction(fp);
              __autoExtFptr.clear();
            };
          }
          wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
          const StructBinder = sqlite3.StructBinder;
          const installMethod = function callee(tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck) {
            if (!(tgt instanceof StructBinder.StructType)) toss("Usage error: target object is-not-a StructType.");else if (!(func instanceof Function) && !wasm.isPtr(func)) toss("Usage error: expecting a Function or WASM pointer to one.");
            if (1 === arguments.length) return (n, f) => callee(tgt, n, f, applyArgcCheck);
            if (!callee.argcProxy) {
              callee.argcProxy = function (tgt, funcName, func, sig) {
                return function (...args) {
                  if (func.length !== arguments.length) toss("Argument mismatch for", tgt.structInfo.name + "::" + funcName + ": Native signature is:", sig);
                  return func.apply(this, args);
                };
              };
              callee.removeFuncList = function () {
                if (this.ondispose.__removeFuncList) {
                  this.ondispose.__removeFuncList.forEach((v, ndx) => {
                    if (wasm.isPtr(v)) try {
                      wasm.uninstallFunction(v);
                    } catch (e) {}
                  });
                  delete this.ondispose.__removeFuncList;
                }
              };
            }
            const sigN = tgt.memberSignature(name);
            if (sigN.length < 2) toss("Member", name, "does not have a function pointer signature:", sigN);
            const memKey = tgt.memberKey(name);
            const fProxy = applyArgcCheck && !wasm.isPtr(func) ? callee.argcProxy(tgt, memKey, func, sigN) : func;
            if (wasm.isPtr(fProxy)) {
              if (fProxy && !wasm.functionEntry(fProxy)) toss("Pointer", fProxy, "is not a WASM function table entry.");
              tgt[memKey] = fProxy;
            } else {
              const pFunc = wasm.installFunction(fProxy, sigN);
              tgt[memKey] = pFunc;
              if (!tgt.ondispose || !tgt.ondispose.__removeFuncList) {
                tgt.addOnDispose("ondispose.__removeFuncList handler", callee.removeFuncList);
                tgt.ondispose.__removeFuncList = [];
              }
              tgt.ondispose.__removeFuncList.push(memKey, pFunc);
            }
            return (n, f) => callee(tgt, n, f, applyArgcCheck);
          };
          installMethod.installMethodArgcCheck = false;
          const installMethods = function (structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck) {
            const seen = /* @__PURE__ */new Map();
            for (const k of Object.keys(methods)) {
              const m = methods[k];
              const prior = seen.get(m);
              if (prior) {
                const mkey = structInstance.memberKey(k);
                structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
              } else {
                installMethod(structInstance, k, m, applyArgcCheck);
                seen.set(m, k);
              }
            }
            return structInstance;
          };
          StructBinder.StructType.prototype.installMethod = function callee(name, func, applyArgcCheck = installMethod.installMethodArgcCheck) {
            return arguments.length < 3 && name && "object" === typeof name ? installMethods(this, ...arguments) : installMethod(this, ...arguments);
          };
          StructBinder.StructType.prototype.installMethods = function (methods, applyArgcCheck = installMethod.installMethodArgcCheck) {
            return installMethods(this, methods, applyArgcCheck);
          };
        });
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {
          const toss3 = (...args) => {
            throw new sqlite3.SQLite3Error(...args);
          };
          const capi = sqlite3.capi,
            wasm = sqlite3.wasm,
            util = sqlite3.util;
          const outWrapper = function (f) {
            return (...args) => f("sqlite3.oo1:", ...args);
          };
          sqlite3.__isUnderTest ? outWrapper(console.debug.bind(console)) : outWrapper(sqlite3.config.debug);
          sqlite3.__isUnderTest ? outWrapper(console.warn.bind(console)) : outWrapper(sqlite3.config.warn);
          sqlite3.__isUnderTest ? outWrapper(console.error.bind(console)) : outWrapper(sqlite3.config.error);
          const __ptrMap = /* @__PURE__ */new WeakMap();
          const __doesNotOwnHandle = /* @__PURE__ */new Set();
          const __stmtMap = /* @__PURE__ */new WeakMap();
          const getOwnOption = (opts, p, dflt) => {
            const d = Object.getOwnPropertyDescriptor(opts, p);
            return d ? d.value : dflt;
          };
          const checkSqlite3Rc = function (dbPtr, sqliteResultCode) {
            if (sqliteResultCode) {
              if (dbPtr instanceof DB) dbPtr = dbPtr.pointer;
              toss3(sqliteResultCode, "sqlite3 result code", sqliteResultCode + ":", dbPtr ? capi.sqlite3_errmsg(dbPtr) : capi.sqlite3_errstr(sqliteResultCode));
            }
            return arguments[0];
          };
          const __dbTraceToConsole = wasm.installFunction("i(ippp)", function (t, c, p, x) {
            if (capi.SQLITE_TRACE_STMT === t) console.log("SQL TRACE #" + ++this.counter, "via sqlite3@" + c + "[" + capi.sqlite3_db_filename(c, null) + "]", wasm.cstrToJs(x));
          }.bind({
            counter: 0
          }));
          const __vfsPostOpenCallback = Object.create(null);
          const dbCtorHelper = function ctor(...args) {
            const opt = ctor.normalizeArgs(...args);
            let pDb;
            if (pDb = opt["sqlite3*"]) {
              if (!opt["sqlite3*:takeOwnership"]) __doesNotOwnHandle.add(this);
              this.filename = capi.sqlite3_db_filename(pDb, "main");
            } else {
              let fn = opt.filename,
                vfsName = opt.vfs,
                flagsStr = opt.flags;
              if ("string" !== typeof fn && !wasm.isPtr(fn) || "string" !== typeof flagsStr || vfsName && "string" !== typeof vfsName && !wasm.isPtr(vfsName)) {
                sqlite3.config.error("Invalid DB ctor args", opt, arguments);
                toss3("Invalid arguments for DB constructor:", arguments, "opts:", opt);
              }
              let oflags = 0;
              if (flagsStr.indexOf("c") >= 0) oflags |= capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE;
              if (flagsStr.indexOf("w") >= 0) oflags |= capi.SQLITE_OPEN_READWRITE;
              if (0 === oflags) oflags |= capi.SQLITE_OPEN_READONLY;
              oflags |= capi.SQLITE_OPEN_EXRESCODE;
              const stack = wasm.pstack.pointer;
              try {
                const pPtr = wasm.pstack.allocPtr();
                let rc = capi.sqlite3_open_v2(fn, pPtr, oflags, vfsName || wasm.ptr.null);
                pDb = wasm.peekPtr(pPtr);
                checkSqlite3Rc(pDb, rc);
                capi.sqlite3_extended_result_codes(pDb, 1);
                if (flagsStr.indexOf("t") >= 0) capi.sqlite3_trace_v2(pDb, capi.SQLITE_TRACE_STMT, __dbTraceToConsole, pDb);
              } catch (e) {
                if (pDb) capi.sqlite3_close_v2(pDb);
                throw e;
              } finally {
                wasm.pstack.restore(stack);
              }
              this.filename = wasm.isPtr(fn) ? wasm.cstrToJs(fn) : fn;
            }
            __ptrMap.set(this, pDb);
            __stmtMap.set(this, Object.create(null));
            if (!opt["sqlite3*"]) try {
              const postInitSql = __vfsPostOpenCallback[capi.sqlite3_js_db_vfs(pDb) || toss3("Internal error: cannot get VFS for new db handle.")];
              if (postInitSql) if (postInitSql instanceof Function) postInitSql(this, sqlite3);else checkSqlite3Rc(pDb, capi.sqlite3_exec(pDb, postInitSql, 0, 0, 0));
            } catch (e) {
              this.close();
              throw e;
            }
          };
          dbCtorHelper.setVfsPostOpenCallback = function (pVfs, callback) {
            if (!(callback instanceof Function)) toss3("dbCtorHelper.setVfsPostOpenCallback() should not be used with a non-function argument.", arguments);
            __vfsPostOpenCallback[pVfs] = callback;
          };
          dbCtorHelper.normalizeArgs = function (filename = ":memory:", flags = "c", vfs = null) {
            const arg = {};
            if (1 === arguments.length && arguments[0] && "object" === typeof arguments[0]) {
              Object.assign(arg, arguments[0]);
              if (void 0 === arg.flags) arg.flags = "c";
              if (void 0 === arg.vfs) arg.vfs = null;
              if (void 0 === arg.filename) arg.filename = ":memory:";
            } else {
              arg.filename = filename;
              arg.flags = flags;
              arg.vfs = vfs;
            }
            return arg;
          };
          const DB = function (...args) {
            dbCtorHelper.apply(this, args);
          };
          DB.dbCtorHelper = dbCtorHelper;
          const BindTypes = {
            null: 1,
            number: 2,
            string: 3,
            boolean: 4,
            blob: 5
          };
          if (wasm.bigIntEnabled) BindTypes.bigint = BindTypes.number;
          const Stmt = function () {
            if (BindTypes !== arguments[2]) toss3(capi.SQLITE_MISUSE, "Do not call the Stmt constructor directly. Use DB.prepare().");
            this.db = arguments[0];
            __ptrMap.set(this, arguments[1]);
            if (arguments.length > 3 && !arguments[3]) __doesNotOwnHandle.add(this);
          };
          const affirmDbOpen = function (db) {
            if (!db.pointer) toss3("DB has been closed.");
            return db;
          };
          const affirmColIndex = function (stmt, ndx) {
            if (ndx !== (ndx | 0) || ndx < 0 || ndx >= stmt.columnCount) toss3("Column index", ndx, "is out of range.");
            return stmt;
          };
          const parseExecArgs = function (db, args) {
            const out = Object.create(null);
            out.opt = Object.create(null);
            switch (args.length) {
              case 1:
                if ("string" === typeof args[0] || util.isSQLableTypedArray(args[0])) out.sql = args[0];else if (Array.isArray(args[0])) out.sql = args[0];else if (args[0] && "object" === typeof args[0]) {
                  out.opt = args[0];
                  out.sql = out.opt.sql;
                }
                break;
              case 2:
                out.sql = args[0];
                out.opt = args[1];
                break;
              default:
                toss3("Invalid argument count for exec().");
            }
            out.sql = util.flexibleString(out.sql);
            if ("string" !== typeof out.sql) toss3("Missing SQL argument or unsupported SQL value type.");
            const opt = out.opt;
            switch (opt.returnValue) {
              case "resultRows":
                if (!opt.resultRows) opt.resultRows = [];
                out.returnVal = () => opt.resultRows;
                break;
              case "saveSql":
                if (!opt.saveSql) opt.saveSql = [];
                out.returnVal = () => opt.saveSql;
                break;
              case void 0:
              case "this":
                out.returnVal = () => db;
                break;
              default:
                toss3("Invalid returnValue value:", opt.returnValue);
            }
            if (!opt.callback && !opt.returnValue && void 0 !== opt.rowMode) {
              if (!opt.resultRows) opt.resultRows = [];
              out.returnVal = () => opt.resultRows;
            }
            if (opt.callback || opt.resultRows) switch (void 0 === opt.rowMode ? "array" : opt.rowMode) {
              case "object":
                out.cbArg = (stmt, cache) => {
                  if (!cache.columnNames) cache.columnNames = stmt.getColumnNames([]);
                  const row = stmt.get([]);
                  const rv = Object.create(null);
                  for (const i in cache.columnNames) rv[cache.columnNames[i]] = row[i];
                  return rv;
                };
                break;
              case "array":
                out.cbArg = stmt => stmt.get([]);
                break;
              case "stmt":
                if (Array.isArray(opt.resultRows)) toss3("exec(): invalid rowMode for a resultRows array: must", "be one of 'array', 'object',", "a result column number, or column name reference.");
                out.cbArg = stmt => stmt;
                break;
              default:
                if (util.isInt32(opt.rowMode)) {
                  out.cbArg = stmt => stmt.get(opt.rowMode);
                  break;
                } else if ("string" === typeof opt.rowMode && opt.rowMode.length > 1 && "$" === opt.rowMode[0]) {
                  const $colName = opt.rowMode.substr(1);
                  out.cbArg = stmt => {
                    const rc = stmt.get(Object.create(null))[$colName];
                    return void 0 === rc ? toss3(capi.SQLITE_NOTFOUND, "exec(): unknown result column:", $colName) : rc;
                  };
                  break;
                }
                toss3("Invalid rowMode:", opt.rowMode);
            }
            return out;
          };
          const __selectFirstRow = (db, sql, bind, ...getArgs) => {
            const stmt = db.prepare(sql);
            try {
              const rc = stmt.bind(bind).step() ? stmt.get(...getArgs) : void 0;
              stmt.reset();
              return rc;
            } finally {
              stmt.finalize();
            }
          };
          const __selectAll = (db, sql, bind, rowMode) => db.exec({
            sql,
            bind,
            rowMode,
            returnValue: "resultRows"
          });
          DB.checkRc = (db, resultCode) => checkSqlite3Rc(db, resultCode);
          DB.prototype = {
            isOpen: function () {
              return !!this.pointer;
            },
            affirmOpen: function () {
              return affirmDbOpen(this);
            },
            close: function () {
              const pDb = this.pointer;
              if (pDb) {
                if (this.onclose && this.onclose.before instanceof Function) try {
                  this.onclose.before(this);
                } catch (e) {}
                Object.keys(__stmtMap.get(this)).forEach((k, s) => {
                  if (s && s.pointer) try {
                    s.finalize();
                  } catch (e) {}
                });
                __ptrMap.delete(this);
                __stmtMap.delete(this);
                if (!__doesNotOwnHandle.delete(this)) capi.sqlite3_close_v2(pDb);
                if (this.onclose && this.onclose.after instanceof Function) try {
                  this.onclose.after(this);
                } catch (e) {}
                delete this.filename;
              }
            },
            changes: function (total = false, sixtyFour = false) {
              const p = affirmDbOpen(this).pointer;
              if (total) return sixtyFour ? capi.sqlite3_total_changes64(p) : capi.sqlite3_total_changes(p);else return sixtyFour ? capi.sqlite3_changes64(p) : capi.sqlite3_changes(p);
            },
            dbFilename: function (dbName = "main") {
              return capi.sqlite3_db_filename(affirmDbOpen(this).pointer, dbName);
            },
            dbName: function (dbNumber = 0) {
              return capi.sqlite3_db_name(affirmDbOpen(this).pointer, dbNumber);
            },
            dbVfsName: function (dbName = 0) {
              let rc;
              const pVfs = capi.sqlite3_js_db_vfs(affirmDbOpen(this).pointer, dbName);
              if (pVfs) {
                const v = new capi.sqlite3_vfs(pVfs);
                try {
                  rc = wasm.cstrToJs(v.$zName);
                } finally {
                  v.dispose();
                }
              }
              return rc;
            },
            prepare: function (sql) {
              affirmDbOpen(this);
              const stack = wasm.pstack.pointer;
              let ppStmt, pStmt;
              try {
                ppStmt = wasm.pstack.alloc(8);
                DB.checkRc(this, capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null));
                pStmt = wasm.peekPtr(ppStmt);
              } finally {
                wasm.pstack.restore(stack);
              }
              if (!pStmt) toss3("Cannot prepare empty SQL.");
              const stmt = new Stmt(this, pStmt, BindTypes);
              __stmtMap.get(this)[pStmt] = stmt;
              return stmt;
            },
            exec: function () {
              affirmDbOpen(this);
              const arg = parseExecArgs(this, arguments);
              if (!arg.sql) return toss3("exec() requires an SQL string.");
              const opt = arg.opt;
              const callback = opt.callback;
              const resultRows = Array.isArray(opt.resultRows) ? opt.resultRows : void 0;
              let stmt;
              let bind = opt.bind;
              let evalFirstResult = !!(arg.cbArg || opt.columnNames || resultRows);
              const stack = wasm.scopedAllocPush();
              const saveSql = Array.isArray(opt.saveSql) ? opt.saveSql : void 0;
              try {
                const isTA = util.isSQLableTypedArray(arg.sql);
                let sqlByteLen = isTA ? arg.sql.byteLength : wasm.jstrlen(arg.sql);
                const ppStmt = wasm.scopedAlloc(2 * wasm.ptr.size + (sqlByteLen + 1));
                const pzTail = wasm.ptr.add(ppStmt, wasm.ptr.size);
                let pSql = wasm.ptr.add(pzTail, wasm.ptr.size);
                const pSqlEnd = wasm.ptr.add(pSql, sqlByteLen);
                if (isTA) wasm.heap8().set(arg.sql, pSql);else wasm.jstrcpy(arg.sql, wasm.heap8(), pSql, sqlByteLen, false);
                wasm.poke8(wasm.ptr.add(pSql, sqlByteLen), 0);
                while (pSql && wasm.peek8(pSql)) {
                  wasm.pokePtr([ppStmt, pzTail], 0);
                  DB.checkRc(this, capi.sqlite3_prepare_v3(this.pointer, pSql, sqlByteLen, 0, ppStmt, pzTail));
                  const pStmt = wasm.peekPtr(ppStmt);
                  pSql = wasm.peekPtr(pzTail);
                  sqlByteLen = Number(wasm.ptr.add(pSqlEnd, -pSql));
                  if (!pStmt) continue;
                  if (saveSql) saveSql.push(capi.sqlite3_sql(pStmt).trim());
                  stmt = new Stmt(this, pStmt, BindTypes);
                  if (bind && stmt.parameterCount) {
                    stmt.bind(bind);
                    bind = null;
                  }
                  if (evalFirstResult && stmt.columnCount) {
                    let gotColNames = Array.isArray(opt.columnNames) ? 0 : 1;
                    evalFirstResult = false;
                    if (arg.cbArg || resultRows) {
                      const cbArgCache = Object.create(null);
                      for (; stmt.step(); __execLock.delete(stmt)) {
                        if (0 === gotColNames++) stmt.getColumnNames(cbArgCache.columnNames = opt.columnNames || []);
                        __execLock.add(stmt);
                        const row = arg.cbArg(stmt, cbArgCache);
                        if (resultRows) resultRows.push(row);
                        if (callback && false === callback.call(opt, row, stmt)) break;
                      }
                      __execLock.delete(stmt);
                    }
                    if (0 === gotColNames) stmt.getColumnNames(opt.columnNames);
                  } else stmt.step();
                  stmt.reset().finalize();
                  stmt = null;
                }
              } finally {
                if (stmt) {
                  __execLock.delete(stmt);
                  stmt.finalize();
                }
                wasm.scopedAllocPop(stack);
              }
              return arg.returnVal();
            },
            createFunction: function f(name, xFunc, opt) {
              const isFunc = f => f instanceof Function;
              switch (arguments.length) {
                case 1:
                  opt = name;
                  name = opt.name;
                  xFunc = opt.xFunc || 0;
                  break;
                case 2:
                  if (!isFunc(xFunc)) {
                    opt = xFunc;
                    xFunc = opt.xFunc || 0;
                  }
                  break;
              }
              if (!opt) opt = {};
              if ("string" !== typeof name) toss3("Invalid arguments: missing function name.");
              let xStep = opt.xStep || 0;
              let xFinal = opt.xFinal || 0;
              const xValue = opt.xValue || 0;
              const xInverse = opt.xInverse || 0;
              let isWindow = void 0;
              if (isFunc(xFunc)) {
                isWindow = false;
                if (isFunc(xStep) || isFunc(xFinal)) toss3("Ambiguous arguments: scalar or aggregate?");
                xStep = xFinal = null;
              } else if (isFunc(xStep)) {
                if (!isFunc(xFinal)) toss3("Missing xFinal() callback for aggregate or window UDF.");
                xFunc = null;
              } else if (isFunc(xFinal)) toss3("Missing xStep() callback for aggregate or window UDF.");else toss3("Missing function-type properties.");
              if (false === isWindow) {
                if (isFunc(xValue) || isFunc(xInverse)) toss3("xValue and xInverse are not permitted for non-window UDFs.");
              } else if (isFunc(xValue)) {
                if (!isFunc(xInverse)) toss3("xInverse must be provided if xValue is.");
                isWindow = true;
              } else if (isFunc(xInverse)) toss3("xValue must be provided if xInverse is.");
              const pApp = opt.pApp;
              if (void 0 !== pApp && null !== pApp && !wasm.isPtr(pApp)) toss3("Invalid value for pApp property. Must be a legal WASM pointer value.");
              const xDestroy = opt.xDestroy || 0;
              if (xDestroy && !isFunc(xDestroy)) toss3("xDestroy property must be a function.");
              let fFlags = 0;
              if (getOwnOption(opt, "deterministic")) fFlags |= capi.SQLITE_DETERMINISTIC;
              if (getOwnOption(opt, "directOnly")) fFlags |= capi.SQLITE_DIRECTONLY;
              if (getOwnOption(opt, "innocuous")) fFlags |= capi.SQLITE_INNOCUOUS;
              name = name.toLowerCase();
              const xArity = xFunc || xStep;
              const arity = getOwnOption(opt, "arity");
              const arityArg = "number" === typeof arity ? arity : xArity.length ? xArity.length - 1 : 0;
              let rc;
              if (isWindow) rc = capi.sqlite3_create_window_function(this.pointer, name, arityArg, capi.SQLITE_UTF8 | fFlags, pApp || 0, xStep, xFinal, xValue, xInverse, xDestroy);else rc = capi.sqlite3_create_function_v2(this.pointer, name, arityArg, capi.SQLITE_UTF8 | fFlags, pApp || 0, xFunc, xStep, xFinal, xDestroy);
              DB.checkRc(this, rc);
              return this;
            },
            selectValue: function (sql, bind, asType) {
              return __selectFirstRow(this, sql, bind, 0, asType);
            },
            selectValues: function (sql, bind, asType) {
              const stmt = this.prepare(sql),
                rc = [];
              try {
                stmt.bind(bind);
                while (stmt.step()) rc.push(stmt.get(0, asType));
                stmt.reset();
              } finally {
                stmt.finalize();
              }
              return rc;
            },
            selectArray: function (sql, bind) {
              return __selectFirstRow(this, sql, bind, []);
            },
            selectObject: function (sql, bind) {
              return __selectFirstRow(this, sql, bind, {});
            },
            selectArrays: function (sql, bind) {
              return __selectAll(this, sql, bind, "array");
            },
            selectObjects: function (sql, bind) {
              return __selectAll(this, sql, bind, "object");
            },
            openStatementCount: function () {
              return this.pointer ? Object.keys(__stmtMap.get(this)).length : 0;
            },
            transaction: function (callback) {
              let opener = "BEGIN";
              if (arguments.length > 1) {
                if (/[^a-zA-Z]/.test(arguments[0])) toss3(capi.SQLITE_MISUSE, "Invalid argument for BEGIN qualifier.");
                opener += " " + arguments[0];
                callback = arguments[1];
              }
              affirmDbOpen(this).exec(opener);
              try {
                const rc = callback(this);
                this.exec("COMMIT");
                return rc;
              } catch (e) {
                this.exec("ROLLBACK");
                throw e;
              }
            },
            savepoint: function (callback) {
              affirmDbOpen(this).exec("SAVEPOINT oo1");
              try {
                const rc = callback(this);
                this.exec("RELEASE oo1");
                return rc;
              } catch (e) {
                this.exec("ROLLBACK to SAVEPOINT oo1; RELEASE SAVEPOINT oo1");
                throw e;
              }
            },
            checkRc: function (resultCode) {
              return checkSqlite3Rc(this, resultCode);
            }
          };
          DB.wrapHandle = function (pDb, takeOwnership = false) {
            if (!pDb || !wasm.isPtr(pDb)) throw new sqlite3.SQLite3Error(capi.SQLITE_MISUSE, "Argument must be a WASM sqlite3 pointer");
            return new DB({
              "sqlite3*": pDb,
              "sqlite3*:takeOwnership": !!takeOwnership
            });
          };
          const affirmStmtOpen = function (stmt) {
            if (!stmt.pointer) toss3("Stmt has been closed.");
            return stmt;
          };
          const isSupportedBindType = function (v) {
            let t = BindTypes[null === v || void 0 === v ? "null" : typeof v];
            switch (t) {
              case BindTypes.boolean:
              case BindTypes.null:
              case BindTypes.number:
              case BindTypes.string:
                return t;
              case BindTypes.bigint:
                return wasm.bigIntEnabled ? t : void 0;
              default:
                return util.isBindableTypedArray(v) ? BindTypes.blob : void 0;
            }
          };
          const affirmSupportedBindType = function (v) {
            return isSupportedBindType(v) || toss3("Unsupported bind() argument type:", typeof v);
          };
          const affirmParamIndex = function (stmt, key) {
            const n = "number" === typeof key ? key : capi.sqlite3_bind_parameter_index(stmt.pointer, key);
            if (0 === n || !util.isInt32(n)) toss3("Invalid bind() parameter name: " + key);else if (n < 1 || n > stmt.parameterCount) toss3("Bind index", key, "is out of range.");
            return n;
          };
          const __execLock = /* @__PURE__ */new Set();
          const __stmtMayGet = /* @__PURE__ */new Set();
          const affirmNotLockedByExec = function (stmt, currentOpName) {
            if (__execLock.has(stmt)) toss3("Operation is illegal when statement is locked:", currentOpName);
            return stmt;
          };
          const bindOne = function f(stmt, ndx, bindType, val) {
            affirmNotLockedByExec(affirmStmtOpen(stmt), "bind()");
            if (!f._) {
              f._tooBigInt = v => toss3("BigInt value is too big to store without precision loss:", v);
              f._ = {
                string: function (stmt, ndx, val, asBlob) {
                  const [pStr, n] = wasm.allocCString(val, true);
                  return (asBlob ? capi.sqlite3_bind_blob : capi.sqlite3_bind_text)(stmt.pointer, ndx, pStr, n, capi.SQLITE_WASM_DEALLOC);
                }
              };
            }
            affirmSupportedBindType(val);
            ndx = affirmParamIndex(stmt, ndx);
            let rc = 0;
            switch (null === val || void 0 === val ? BindTypes.null : bindType) {
              case BindTypes.null:
                rc = capi.sqlite3_bind_null(stmt.pointer, ndx);
                break;
              case BindTypes.string:
                rc = f._.string(stmt, ndx, val, false);
                break;
              case BindTypes.number:
                {
                  let m;
                  if (util.isInt32(val)) m = capi.sqlite3_bind_int;else if ("bigint" === typeof val) {
                    if (!util.bigIntFits64(val)) f._tooBigInt(val);else if (wasm.bigIntEnabled) m = capi.sqlite3_bind_int64;else if (util.bigIntFitsDouble(val)) {
                      val = Number(val);
                      m = capi.sqlite3_bind_double;
                    } else f._tooBigInt(val);
                  } else {
                    val = Number(val);
                    if (wasm.bigIntEnabled && Number.isInteger(val)) m = capi.sqlite3_bind_int64;else m = capi.sqlite3_bind_double;
                  }
                  rc = m(stmt.pointer, ndx, val);
                  break;
                }
              case BindTypes.boolean:
                rc = capi.sqlite3_bind_int(stmt.pointer, ndx, val ? 1 : 0);
                break;
              case BindTypes.blob:
                {
                  if ("string" === typeof val) {
                    rc = f._.string(stmt, ndx, val, true);
                    break;
                  } else if (val instanceof ArrayBuffer) val = new Uint8Array(val);else if (!util.isBindableTypedArray(val)) toss3("Binding a value as a blob requires", "that it be a string, Uint8Array, Int8Array, or ArrayBuffer.");
                  const pBlob = wasm.alloc(val.byteLength || 1);
                  wasm.heap8().set(val.byteLength ? val : [0], Number(pBlob));
                  rc = capi.sqlite3_bind_blob(stmt.pointer, ndx, pBlob, val.byteLength, capi.SQLITE_WASM_DEALLOC);
                  break;
                }
              default:
                sqlite3.config.warn("Unsupported bind() argument type:", val);
                toss3("Unsupported bind() argument type: " + typeof val);
            }
            if (rc) DB.checkRc(stmt.db.pointer, rc);
            return stmt;
          };
          Stmt.prototype = {
            finalize: function () {
              const ptr = this.pointer;
              if (ptr) {
                affirmNotLockedByExec(this, "finalize()");
                const rc = __doesNotOwnHandle.delete(this) ? 0 : capi.sqlite3_finalize(ptr);
                delete __stmtMap.get(this.db)[ptr];
                __ptrMap.delete(this);
                __execLock.delete(this);
                __stmtMayGet.delete(this);
                delete this.parameterCount;
                delete this.db;
                return rc;
              }
            },
            clearBindings: function () {
              affirmNotLockedByExec(affirmStmtOpen(this), "clearBindings()");
              capi.sqlite3_clear_bindings(this.pointer);
              __stmtMayGet.delete(this);
              return this;
            },
            reset: function (alsoClearBinds) {
              affirmNotLockedByExec(this, "reset()");
              if (alsoClearBinds) this.clearBindings();
              const rc = capi.sqlite3_reset(affirmStmtOpen(this).pointer);
              __stmtMayGet.delete(this);
              checkSqlite3Rc(this.db, rc);
              return this;
            },
            bind: function () {
              affirmStmtOpen(this);
              let ndx, arg;
              switch (arguments.length) {
                case 1:
                  ndx = 1;
                  arg = arguments[0];
                  break;
                case 2:
                  ndx = arguments[0];
                  arg = arguments[1];
                  break;
                default:
                  toss3("Invalid bind() arguments.");
              }
              if (void 0 === arg) return this;else if (!this.parameterCount) toss3("This statement has no bindable parameters.");
              __stmtMayGet.delete(this);
              if (null === arg) return bindOne(this, ndx, BindTypes.null, arg);else if (Array.isArray(arg)) {
                if (1 !== arguments.length) toss3("When binding an array, an index argument is not permitted.");
                arg.forEach((v, i) => bindOne(this, i + 1, affirmSupportedBindType(v), v));
                return this;
              } else if (arg instanceof ArrayBuffer) arg = new Uint8Array(arg);
              if ("object" === typeof arg && !util.isBindableTypedArray(arg)) {
                if (1 !== arguments.length) toss3("When binding an object, an index argument is not permitted.");
                Object.keys(arg).forEach(k => bindOne(this, k, affirmSupportedBindType(arg[k]), arg[k]));
                return this;
              } else return bindOne(this, ndx, affirmSupportedBindType(arg), arg);
            },
            bindAsBlob: function (ndx, arg) {
              affirmStmtOpen(this);
              if (1 === arguments.length) {
                arg = ndx;
                ndx = 1;
              }
              const t = affirmSupportedBindType(arg);
              if (BindTypes.string !== t && BindTypes.blob !== t && BindTypes.null !== t) toss3("Invalid value type for bindAsBlob()");
              return bindOne(this, ndx, BindTypes.blob, arg);
            },
            step: function () {
              affirmNotLockedByExec(this, "step()");
              const rc = capi.sqlite3_step(affirmStmtOpen(this).pointer);
              switch (rc) {
                case capi.SQLITE_DONE:
                  __stmtMayGet.delete(this);
                  return false;
                case capi.SQLITE_ROW:
                  __stmtMayGet.add(this);
                  return true;
                default:
                  __stmtMayGet.delete(this);
                  sqlite3.config.warn("sqlite3_step() rc=", rc, capi.sqlite3_js_rc_str(rc), "SQL =", capi.sqlite3_sql(this.pointer));
                  DB.checkRc(this.db.pointer, rc);
              }
            },
            stepReset: function () {
              this.step();
              return this.reset();
            },
            stepFinalize: function () {
              try {
                const rc = this.step();
                this.reset();
                return rc;
              } finally {
                try {
                  this.finalize();
                } catch (e) {}
              }
            },
            get: function (ndx, asType) {
              if (!__stmtMayGet.has(affirmStmtOpen(this))) toss3("Stmt.step() has not (recently) returned true.");
              if (Array.isArray(ndx)) {
                let i = 0;
                const n = this.columnCount;
                while (i < n) ndx[i] = this.get(i++);
                return ndx;
              } else if (ndx && "object" === typeof ndx) {
                let i = 0;
                const n = this.columnCount;
                while (i < n) ndx[capi.sqlite3_column_name(this.pointer, i)] = this.get(i++);
                return ndx;
              }
              affirmColIndex(this, ndx);
              switch (void 0 === asType ? capi.sqlite3_column_type(this.pointer, ndx) : asType) {
                case capi.SQLITE_NULL:
                  return null;
                case capi.SQLITE_INTEGER:
                  if (wasm.bigIntEnabled) {
                    const rc = capi.sqlite3_column_int64(this.pointer, ndx);
                    if (rc >= Number.MIN_SAFE_INTEGER && rc <= Number.MAX_SAFE_INTEGER) return Number(rc).valueOf();
                    return rc;
                  } else {
                    const rc = capi.sqlite3_column_double(this.pointer, ndx);
                    if (rc > Number.MAX_SAFE_INTEGER || rc < Number.MIN_SAFE_INTEGER) toss3("Integer is out of range for JS integer range: " + rc);
                    return util.isInt32(rc) ? rc | 0 : rc;
                  }
                case capi.SQLITE_FLOAT:
                  return capi.sqlite3_column_double(this.pointer, ndx);
                case capi.SQLITE_TEXT:
                  return capi.sqlite3_column_text(this.pointer, ndx);
                case capi.SQLITE_BLOB:
                  {
                    const n = capi.sqlite3_column_bytes(this.pointer, ndx),
                      ptr = capi.sqlite3_column_blob(this.pointer, ndx),
                      rc = new Uint8Array(n);
                    if (n) {
                      rc.set(wasm.heap8u().slice(Number(ptr), Number(ptr) + n), 0);
                      if (this.db._blobXfer instanceof Array) this.db._blobXfer.push(rc.buffer);
                    }
                    return rc;
                  }
                default:
                  toss3("Don't know how to translate", "type of result column #" + ndx + ".");
              }
              toss3("Not reached.");
            },
            getInt: function (ndx) {
              return this.get(ndx, capi.SQLITE_INTEGER);
            },
            getFloat: function (ndx) {
              return this.get(ndx, capi.SQLITE_FLOAT);
            },
            getString: function (ndx) {
              return this.get(ndx, capi.SQLITE_TEXT);
            },
            getBlob: function (ndx) {
              return this.get(ndx, capi.SQLITE_BLOB);
            },
            getJSON: function (ndx) {
              const s = this.get(ndx, capi.SQLITE_STRING);
              return null === s ? s : JSON.parse(s);
            },
            getColumnName: function (ndx) {
              return capi.sqlite3_column_name(affirmColIndex(affirmStmtOpen(this), ndx).pointer, ndx);
            },
            getColumnNames: function (tgt = []) {
              affirmColIndex(affirmStmtOpen(this), 0);
              const n = this.columnCount;
              for (let i = 0; i < n; ++i) tgt.push(capi.sqlite3_column_name(this.pointer, i));
              return tgt;
            },
            getParamIndex: function (name) {
              return affirmStmtOpen(this).parameterCount ? capi.sqlite3_bind_parameter_index(this.pointer, name) : void 0;
            },
            getParamName: function (ndx) {
              return affirmStmtOpen(this).parameterCount ? capi.sqlite3_bind_parameter_name(this.pointer, ndx) : void 0;
            },
            isBusy: function () {
              return 0 !== capi.sqlite3_stmt_busy(affirmStmtOpen(this));
            },
            isReadOnly: function () {
              return 0 !== capi.sqlite3_stmt_readonly(affirmStmtOpen(this));
            }
          };
          {
            const prop = {
              enumerable: true,
              get: function () {
                return __ptrMap.get(this);
              },
              set: () => toss3("The pointer property is read-only.")
            };
            Object.defineProperty(Stmt.prototype, "pointer", prop);
            Object.defineProperty(DB.prototype, "pointer", prop);
          }
          Object.defineProperty(Stmt.prototype, "columnCount", {
            enumerable: false,
            get: function () {
              return capi.sqlite3_column_count(this.pointer);
            },
            set: () => toss3("The columnCount property is read-only.")
          });
          Object.defineProperty(Stmt.prototype, "parameterCount", {
            enumerable: false,
            get: function () {
              return capi.sqlite3_bind_parameter_count(this.pointer);
            },
            set: () => toss3("The parameterCount property is read-only.")
          });
          Stmt.wrapHandle = function (oo1db, pStmt, takeOwnership = false) {
            if (!(oo1db instanceof DB) || !oo1db.pointer) throw new sqlite3.SQLite3Error(sqlite3.SQLITE_MISUSE, "First argument must be an opened sqlite3.oo1.DB instance");
            if (!pStmt || !wasm.isPtr(pStmt)) throw new sqlite3.SQLite3Error(sqlite3.SQLITE_MISUSE, "Second argument must be a WASM sqlite3_stmt pointer");
            return new Stmt(oo1db, pStmt, BindTypes, !!takeOwnership);
          };
          sqlite3.oo1 = {
            DB,
            Stmt
          };
        });
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {
          const util = sqlite3.util;
          sqlite3.initWorker1API = function () {

            const toss = (...args) => {
              throw new Error(args.join(" "));
            };
            if (!(globalThis.WorkerGlobalScope instanceof Function)) toss("initWorker1API() must be run from a Worker thread.");
            const sqlite3 = this.sqlite3 || toss("Missing this.sqlite3 object.");
            const DB = sqlite3.oo1.DB;
            const getDbId = function (db) {
              let id = wState.idMap.get(db);
              if (id) return id;
              id = "db#" + ++wState.idSeq + ":" + Math.floor(Math.random() * 1e8) + ":" + Math.floor(Math.random() * 1e8);
              wState.idMap.set(db, id);
              return id;
            };
            const wState = {
              dbList: [],
              idSeq: 0,
              idMap: /* @__PURE__ */new WeakMap(),
              xfer: [],
              open: function (opt) {
                const db = new DB(opt);
                this.dbs[getDbId(db)] = db;
                if (this.dbList.indexOf(db) < 0) this.dbList.push(db);
                return db;
              },
              close: function (db, alsoUnlink) {
                if (db) {
                  delete this.dbs[getDbId(db)];
                  const filename = db.filename;
                  const pVfs = util.sqlite3__wasm_db_vfs(db.pointer, 0);
                  db.close();
                  const ddNdx = this.dbList.indexOf(db);
                  if (ddNdx >= 0) this.dbList.splice(ddNdx, 1);
                  if (alsoUnlink && filename && pVfs) util.sqlite3__wasm_vfs_unlink(pVfs, filename);
                }
              },
              post: function (msg, xferList) {
                if (xferList && xferList.length) {
                  globalThis.postMessage(msg, Array.from(xferList));
                  xferList.length = 0;
                } else globalThis.postMessage(msg);
              },
              dbs: Object.create(null),
              getDb: function (id, require = true) {
                return this.dbs[id] || (require ? toss("Unknown (or closed) DB ID:", id) : void 0);
              }
            };
            const affirmDbOpen = function (db = wState.dbList[0]) {
              return db && db.pointer ? db : toss("DB is not opened.");
            };
            const getMsgDb = function (msgData, affirmExists = true) {
              const db = wState.getDb(msgData.dbId, false) || wState.dbList[0];
              return affirmExists ? affirmDbOpen(db) : db;
            };
            const getDefaultDbId = function () {
              return wState.dbList[0] && getDbId(wState.dbList[0]);
            };
            const wMsgHandler = {
              open: function (ev) {
                const oargs = Object.create(null),
                  args = ev.args || Object.create(null);
                if (args.simulateError) toss("Throwing because of simulateError flag.");
                const rc = Object.create(null);
                oargs.vfs = args.vfs;
                oargs.filename = args.filename || "";
                const db = wState.open(oargs);
                rc.filename = db.filename;
                rc.persistent = !!sqlite3.capi.sqlite3_js_db_uses_vfs(db.pointer, "opfs");
                rc.dbId = getDbId(db);
                rc.vfs = db.dbVfsName();
                return rc;
              },
              close: function (ev) {
                const db = getMsgDb(ev, false);
                const response = {
                  filename: db && db.filename
                };
                if (db) {
                  const doUnlink = ev.args && "object" === typeof ev.args ? !!ev.args.unlink : false;
                  wState.close(db, doUnlink);
                }
                return response;
              },
              exec: function (ev) {
                const rc = "string" === typeof ev.args ? {
                  sql: ev.args
                } : ev.args || Object.create(null);
                if ("stmt" === rc.rowMode) toss("Invalid rowMode for 'exec': stmt mode", "does not work in the Worker API.");else if (!rc.sql) toss("'exec' requires input SQL.");
                const db = getMsgDb(ev);
                if (rc.callback || Array.isArray(rc.resultRows)) db._blobXfer = wState.xfer;
                const theCallback = rc.callback;
                let rowNumber = 0;
                const hadColNames = !!rc.columnNames;
                if ("string" === typeof theCallback) {
                  if (!hadColNames) rc.columnNames = [];
                  rc.callback = function (row, stmt) {
                    wState.post({
                      type: theCallback,
                      columnNames: rc.columnNames,
                      rowNumber: ++rowNumber,
                      row
                    }, wState.xfer);
                  };
                }
                try {
                  const changeCount = !!rc.countChanges ? db.changes(true, 64 === rc.countChanges) : void 0;
                  db.exec(rc);
                  if (void 0 !== changeCount) rc.changeCount = db.changes(true, 64 === rc.countChanges) - changeCount;
                  const lastInsertRowId = !!rc.lastInsertRowId ? sqlite3.capi.sqlite3_last_insert_rowid(db) : void 0;
                  if (void 0 !== lastInsertRowId) rc.lastInsertRowId = lastInsertRowId;
                  if (rc.callback instanceof Function) {
                    rc.callback = theCallback;
                    wState.post({
                      type: theCallback,
                      columnNames: rc.columnNames,
                      rowNumber: null,
                      row: void 0
                    });
                  }
                } finally {
                  delete db._blobXfer;
                  if (rc.callback) rc.callback = theCallback;
                }
                return rc;
              },
              "config-get": function () {
                const rc = Object.create(null),
                  src = sqlite3.config;
                ["bigIntEnabled"].forEach(function (k) {
                  if (Object.getOwnPropertyDescriptor(src, k)) rc[k] = src[k];
                });
                rc.version = sqlite3.version;
                rc.vfsList = sqlite3.capi.sqlite3_js_vfs_list();
                return rc;
              },
              export: function (ev) {
                const db = getMsgDb(ev);
                const response = {
                  byteArray: sqlite3.capi.sqlite3_js_db_export(db.pointer),
                  filename: db.filename,
                  mimetype: "application/x-sqlite3"
                };
                wState.xfer.push(response.byteArray.buffer);
                return response;
              },
              toss: function (ev) {
                toss("Testing worker exception");
              }
            };
            globalThis.onmessage = async function (ev) {
              ev = ev.data;
              let result,
                dbId = ev.dbId,
                evType = ev.type;
              const arrivalTime = performance.now();
              try {
                if (wMsgHandler.hasOwnProperty(evType) && wMsgHandler[evType] instanceof Function) result = await wMsgHandler[evType](ev);else toss("Unknown db worker message type:", ev.type);
              } catch (err) {
                evType = "error";
                result = {
                  operation: ev.type,
                  message: err.message,
                  errorClass: err.name,
                  input: ev
                };
                if (err.stack) result.stack = "string" === typeof err.stack ? err.stack.split(/\n\s*/) : err.stack;
              }
              if (!dbId) dbId = result.dbId || getDefaultDbId();
              wState.post({
                type: evType,
                dbId,
                messageId: ev.messageId,
                workerReceivedTime: arrivalTime,
                workerRespondTime: performance.now(),
                departureTime: ev.departureTime,
                result
              }, wState.xfer);
            };
            globalThis.postMessage({
              type: "sqlite3-api",
              result: "worker1-ready"
            });
          }.bind({
            sqlite3
          });
        });
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {
          const wasm = sqlite3.wasm,
            capi = sqlite3.capi,
            toss = sqlite3.util.toss3;
          const vfs = Object.create(null);
          sqlite3.vfs = vfs;
          capi.sqlite3_vfs.prototype.registerVfs = function (asDefault = false) {
            if (!(this instanceof sqlite3.capi.sqlite3_vfs)) toss("Expecting a sqlite3_vfs-type argument.");
            const rc = capi.sqlite3_vfs_register(this, asDefault ? 1 : 0);
            if (rc) toss("sqlite3_vfs_register(", this, ") failed with rc", rc);
            if (this.pointer !== capi.sqlite3_vfs_find(this.$zName)) toss("BUG: sqlite3_vfs_find(vfs.$zName) failed for just-installed VFS", this);
            return this;
          };
          vfs.installVfs = function (opt) {
            let count = 0;
            const propList = ["io", "vfs"];
            for (const key of propList) {
              const o = opt[key];
              if (o) {
                ++count;
                o.struct.installMethods(o.methods, !!o.applyArgcCheck);
                if ("vfs" === key) {
                  if (!o.struct.$zName && "string" === typeof o.name) o.struct.addOnDispose(o.struct.$zName = wasm.allocCString(o.name));
                  o.struct.registerVfs(!!o.asDefault);
                }
              }
            }
            if (!count) toss("Misuse: installVfs() options object requires at least", "one of:", propList);
            return this;
          };
        });
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {
          if (!sqlite3.wasm.exports.sqlite3_declare_vtab) return;
          const wasm = sqlite3.wasm,
            capi = sqlite3.capi,
            toss = sqlite3.util.toss3;
          const vtab = Object.create(null);
          sqlite3.vtab = vtab;
          const sii = capi.sqlite3_index_info;
          sii.prototype.nthConstraint = function (n, asPtr = false) {
            if (n < 0 || n >= this.$nConstraint) return false;
            const ptr = wasm.ptr.add(this.$aConstraint, sii.sqlite3_index_constraint.structInfo.sizeof * n);
            return asPtr ? ptr : new sii.sqlite3_index_constraint(ptr);
          };
          sii.prototype.nthConstraintUsage = function (n, asPtr = false) {
            if (n < 0 || n >= this.$nConstraint) return false;
            const ptr = wasm.ptr.add(this.$aConstraintUsage, sii.sqlite3_index_constraint_usage.structInfo.sizeof * n);
            return asPtr ? ptr : new sii.sqlite3_index_constraint_usage(ptr);
          };
          sii.prototype.nthOrderBy = function (n, asPtr = false) {
            if (n < 0 || n >= this.$nOrderBy) return false;
            const ptr = wasm.ptr.add(this.$aOrderBy, sii.sqlite3_index_orderby.structInfo.sizeof * n);
            return asPtr ? ptr : new sii.sqlite3_index_orderby(ptr);
          };
          const __xWrapFactory = function (methodName, StructType) {
            return function (ptr, removeMapping = false) {
              if (0 === arguments.length) ptr = new StructType();
              if (ptr instanceof StructType) {
                this.set(ptr.pointer, ptr);
                return ptr;
              } else if (!wasm.isPtr(ptr)) sqlite3.SQLite3Error.toss("Invalid argument to", methodName + "()");
              let rc = this.get(ptr);
              if (removeMapping) this.delete(ptr);
              return rc;
            }.bind(/* @__PURE__ */new Map());
          };
          const StructPtrMapper = function (name, StructType) {
            const __xWrap = __xWrapFactory(name, StructType);
            return Object.assign(Object.create(null), {
              StructType,
              create: ppOut => {
                const rc = __xWrap();
                wasm.pokePtr(ppOut, rc.pointer);
                return rc;
              },
              get: pCObj => __xWrap(pCObj),
              unget: pCObj => __xWrap(pCObj, true),
              dispose: pCObj => __xWrap(pCObj, true)?.dispose?.()
            });
          };
          vtab.xVtab = StructPtrMapper("xVtab", capi.sqlite3_vtab);
          vtab.xCursor = StructPtrMapper("xCursor", capi.sqlite3_vtab_cursor);
          vtab.xIndexInfo = pIdxInfo => new capi.sqlite3_index_info(pIdxInfo);
          vtab.xError = function f(methodName, err, defaultRc) {
            if (f.errorReporter instanceof Function) try {
              f.errorReporter("sqlite3_module::" + methodName + "(): " + err.message);
            } catch (e) {}
            let rc;
            if (err instanceof sqlite3.WasmAllocError) rc = capi.SQLITE_NOMEM;else if (arguments.length > 2) rc = defaultRc;else if (err instanceof sqlite3.SQLite3Error) rc = err.resultCode;
            return rc || capi.SQLITE_ERROR;
          };
          vtab.xError.errorReporter = sqlite3.config.error.bind(sqlite3.config);
          vtab.xRowid = (ppRowid64, value) => wasm.poke(ppRowid64, value, "i64");
          vtab.setupModule = function (opt) {
            let createdMod = false;
            const mod = this instanceof capi.sqlite3_module ? this : opt.struct || (createdMod = new capi.sqlite3_module());
            try {
              const methods = opt.methods || toss("Missing 'methods' object.");
              for (const e of Object.entries({
                xConnect: "xCreate",
                xDisconnect: "xDestroy"
              })) {
                const k = e[0],
                  v = e[1];
                if (true === methods[k]) methods[k] = methods[v];else if (true === methods[v]) methods[v] = methods[k];
              }
              if (opt.catchExceptions) {
                const fwrap = function (methodName, func) {
                  if (["xConnect", "xCreate"].indexOf(methodName) >= 0) return function (pDb, pAux, argc, argv, ppVtab, pzErr) {
                    try {
                      return func(...arguments) || 0;
                    } catch (e) {
                      if (!(e instanceof sqlite3.WasmAllocError)) {
                        wasm.dealloc(wasm.peekPtr(pzErr));
                        wasm.pokePtr(pzErr, wasm.allocCString(e.message));
                      }
                      return vtab.xError(methodName, e);
                    }
                  };else return function (...args) {
                    try {
                      return func(...args) || 0;
                    } catch (e) {
                      return vtab.xError(methodName, e);
                    }
                  };
                };
                const mnames = ["xCreate", "xConnect", "xBestIndex", "xDisconnect", "xDestroy", "xOpen", "xClose", "xFilter", "xNext", "xEof", "xColumn", "xRowid", "xUpdate", "xBegin", "xSync", "xCommit", "xRollback", "xFindFunction", "xRename", "xSavepoint", "xRelease", "xRollbackTo", "xShadowName"];
                const remethods = Object.create(null);
                for (const k of mnames) {
                  const m = methods[k];
                  if (!(m instanceof Function)) continue;else if ("xConnect" === k && methods.xCreate === m) remethods[k] = methods.xCreate;else if ("xCreate" === k && methods.xConnect === m) remethods[k] = methods.xConnect;else remethods[k] = fwrap(k, m);
                }
                mod.installMethods(remethods, false);
              } else mod.installMethods(methods, !!opt.applyArgcCheck);
              if (0 === mod.$iVersion) {
                let v;
                if ("number" === typeof opt.iVersion) v = opt.iVersion;else if (mod.$xIntegrity) v = 4;else if (mod.$xShadowName) v = 3;else if (mod.$xSavePoint || mod.$xRelease || mod.$xRollbackTo) v = 2;else v = 1;
                mod.$iVersion = v;
              }
            } catch (e) {
              if (createdMod) createdMod.dispose();
              throw e;
            }
            return mod;
          };
          capi.sqlite3_module.prototype.setupModule = function (opt) {
            return vtab.setupModule.call(this, opt);
          };
        });
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {

          const capi = sqlite3.capi,
            sqlite3_kvvfs_methods = capi.sqlite3_kvvfs_methods,
            KVVfsFile = capi.KVVfsFile,
            pKvvfs = sqlite3.capi.sqlite3_vfs_find("kvvfs");
          delete capi.sqlite3_kvvfs_methods;
          delete capi.KVVfsFile;
          if (!pKvvfs) return;
          const util = sqlite3.util,
            wasm = sqlite3.wasm,
            toss3 = util.toss3,
            hop = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
          const kvvfsMethods = new sqlite3_kvvfs_methods(wasm.exports.sqlite3__wasm_kvvfs_methods());
          util.assert(32 <= kvvfsMethods.$nKeySize, "unexpected kvvfsMethods.$nKeySize: " + kvvfsMethods.$nKeySize);
          const cache = Object.assign(Object.create(null), {
            rxJournalSuffix: /-journal$/,
            zKeyJrnl: wasm.allocCString("jrnl"),
            zKeySz: wasm.allocCString("sz"),
            keySize: kvvfsMethods.$nKeySize,
            buffer: Object.assign(Object.create(null), {
              n: kvvfsMethods.$nBufferSize,
              pool: Object.create(null)
            })
          });
          cache.memBuffer = (id = 0) => cache.buffer.pool[id] ??= wasm.alloc(cache.buffer.n);
          cache.memBufferFree = id => {
            const b = cache.buffer.pool[id];
            if (b) {
              wasm.dealloc(b);
              delete cache.buffer.pool[id];
            }
          };
          const noop = () => {};
          const debug = sqlite3.__isUnderTest ? (...args) => sqlite3.config.debug("kvvfs:", ...args) : noop;
          const warn = (...args) => sqlite3.config.warn("kvvfs:", ...args);
          const error = (...args) => sqlite3.config.error("kvvfs:", ...args);
          class KVVfsStorage {
            #map;
            #keys;
            #getKeys() {
              return this.#keys ??= Object.keys(this.#map);
            }
            constructor() {
              this.clear();
            }
            key(n) {
              const k = this.#getKeys();
              return n < k.length ? k[n] : null;
            }
            getItem(k) {
              return this.#map[k] ?? null;
            }
            setItem(k, v) {
              if (!hop(this.#map, k)) this.#keys = null;
              this.#map[k] = "" + v;
            }
            removeItem(k) {
              if (delete this.#map[k]) this.#keys = null;
            }
            clear() {
              this.#map = Object.create(null);
              this.#keys = null;
            }
            get length() {
              return this.#getKeys().length;
            }
          }
          const kvvfsIsPersistentName = v => "local" === v || "session" === v;
          const kvvfsKeyPrefix = v => kvvfsIsPersistentName(v) ? "kvvfs-" + v + "-" : "";
          const validateStorageName = function (n, mayBeJournal = false) {
            if (kvvfsIsPersistentName(n)) return;
            const len = new Blob([n]).size;
            if (!len) toss3(capi.SQLITE_MISUSE, "Empty name is not permitted.");
            let maxLen = cache.keySize - 1;
            if (cache.rxJournalSuffix.test(n)) {
              if (!mayBeJournal) toss3(capi.SQLITE_MISUSE, "Storage names may not have a '-journal' suffix.");
            } else if (["-wal", "-shm"].filter(v => n.endsWith(v)).length) toss3(capi.SQLITE_MISUSE, "Storage names may not have a -wal or -shm suffix.");else maxLen -= 8;
            if (len > maxLen) toss3(capi.SQLITE_RANGE, "Storage name is too long. Limit =", maxLen);
            let i;
            for (i = 0; i < len; ++i) {
              const ch = n.codePointAt(i);
              if (ch < 32) toss3(capi.SQLITE_RANGE, "Illegal character (" + ch + "d) in storage name:", n);
            }
          };
          const newStorageObj = (name, storage = void 0) => Object.assign(Object.create(null), {
            jzClass: name,
            refc: 1,
            deleteAtRefc0: false,
            storage: storage || new KVVfsStorage(),
            keyPrefix: kvvfsKeyPrefix(name),
            files: [],
            listeners: void 0
          });
          const kvvfs = sqlite3.kvvfs = Object.create(null);
          if (sqlite3.__isUnderTest) kvvfs.log = Object.assign(Object.create(null), {
            xOpen: false,
            xClose: false,
            xWrite: false,
            xRead: false,
            xSync: false,
            xAccess: false,
            xFileControl: false,
            xRcrdRead: false,
            xRcrdWrite: false,
            xRcrdDelete: false
          });
          const deleteStorage = function (store) {
            const other = cache.rxJournalSuffix.test(store.jzClass) ? store.jzClass.replace(cache.rxJournalSuffix, "") : store.jzClass + "-journal";
            kvvfs?.log?.xClose && debug("cleaning up storage handles [", store.jzClass, other, "]", store);
            delete cache.storagePool[store.jzClass];
            delete cache.storagePool[other];
            if (!sqlite3.__isUnderTest) {
              delete store.storage;
              delete store.refc;
            }
          };
          const installStorageAndJournal = store => cache.storagePool[store.jzClass] = cache.storagePool[store.jzClass + "-journal"] = store;
          const nameOfThisThreadStorage = ".";
          cache.storagePool = Object.assign(Object.create(null), {
            [nameOfThisThreadStorage]: newStorageObj(nameOfThisThreadStorage)
          });
          if (globalThis.Storage) {
            if (globalThis.localStorage instanceof globalThis.Storage) cache.storagePool.local = newStorageObj("local", globalThis.localStorage);
            if (globalThis.sessionStorage instanceof globalThis.Storage) cache.storagePool.session = newStorageObj("session", globalThis.sessionStorage);
          }
          cache.builtinStorageNames = Object.keys(cache.storagePool);
          const isBuiltinName = n => cache.builtinStorageNames.indexOf(n) > -1;
          for (const k of Object.keys(cache.storagePool)) {
            const orig = cache.storagePool[k];
            cache.storagePool[k + "-journal"] = orig;
          }
          cache.setError = (e = void 0, dfltErrCode = capi.SQLITE_ERROR) => {
            if (e) {
              cache.lastError = e;
              return e.resultCode | 0 || dfltErrCode;
            }
            delete cache.lastError;
            return 0;
          };
          cache.popError = () => {
            const e = cache.lastError;
            delete cache.lastError;
            return e;
          };
          const catchForNotify = e => {
            warn("kvvfs.listener handler threw:", e);
          };
          const kvvfsDecode = wasm.exports.sqlite3__wasm_kvvfs_decode;
          const kvvfsEncode = wasm.exports.sqlite3__wasm_kvvfs_encode;
          const notifyListeners = async function (eventName, store, ...args) {
            try {
              if (store.keyPrefix && args[0]) args[0] = args[0].replace(store.keyPrefix, "");
              let u8enc, z0, z1, wcache;
              for (const ear of store.listeners) {
                const ev = Object.create(null);
                ev.storageName = store.jzClass;
                ev.type = eventName;
                ear.decodePages;
                const f = ear.events[eventName];
                if (f) {
                  if (!ear.includeJournal && args[0] === "jrnl") continue;
                  if ("write" === eventName && ear.decodePages && +args[0] > 0) {
                    ev.data = [args[0]];
                    if (wcache?.[args[0]]) {
                      ev.data[1] = wcache[args[0]];
                      continue;
                    }
                    u8enc ??= new TextEncoder("utf-8");
                    z0 ??= cache.memBuffer(10);
                    z1 ??= cache.memBuffer(11);
                    const u = u8enc.encode(args[1]);
                    const heap = wasm.heap8u();
                    heap.set(u, Number(z0));
                    heap[wasm.ptr.addn(z0, u.length)] = 0;
                    const rc = kvvfsDecode(z0, z1, cache.buffer.n);
                    if (rc > 0) {
                      wcache ??= Object.create(null);
                      wcache[args[0]] = ev.data[1] = heap.slice(Number(z1), wasm.ptr.addn(z1, rc));
                    } else continue;
                  } else ev.data = args.length ? args.length === 1 ? args[0] : args : void 0;
                  try {
                    f(ev)?.catch?.(catchForNotify);
                  } catch (e) {
                    warn("notifyListeners [", store.jzClass, "]", eventName, e);
                  }
                }
              }
            } catch (e) {
              catchForNotify(e);
            }
          };
          const storageForZClass = zClass => "string" === typeof zClass ? cache.storagePool[zClass] : cache.storagePool[wasm.cstrToJs(zClass)];
          const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKey;
          const zKeyForStorage = (store, zClass, zKey) => {
            return zClass && store.keyPrefix ? kvvfsMakeKey(zClass, zKey) : zKey;
          };
          const jsKeyForStorage = (store, zClass, zKey) => wasm.cstrToJs(zKeyForStorage(store, zClass, zKey));
          const storageGetDbSize = store => +store.storage.getItem(store.keyPrefix + "sz");
          const pFileHandles = /* @__PURE__ */new Map();
          const originalMethods = {
            vfs: Object.create(null),
            ioDb: Object.create(null),
            ioJrnl: Object.create(null)
          };
          const pVfs = new capi.sqlite3_vfs(kvvfsMethods.$pVfs);
          const pIoDb = new capi.sqlite3_io_methods(kvvfsMethods.$pIoDb);
          const pIoJrnl = new capi.sqlite3_io_methods(kvvfsMethods.$pIoJrnl);
          const recordHandler = Object.create(null);
          const kvvfsInternal = Object.assign(Object.create(null), {
            pFileHandles,
            cache,
            storageForZClass,
            KVVfsStorage,
            disablePageSizeChange: true
          });
          if (kvvfs.log) kvvfs.internal = kvvfsInternal;
          const methodOverrides = {
            recordHandler: {
              xRcrdRead: (zClass, zKey, zBuf, nBuf) => {
                try {
                  const jzClass = wasm.cstrToJs(zClass);
                  const store = storageForZClass(jzClass);
                  if (!store) return -1;
                  const jXKey = jsKeyForStorage(store, zClass, zKey);
                  kvvfs?.log?.xRcrdRead && warn("xRcrdRead", jzClass, jXKey, nBuf, store);
                  const jV = store.storage.getItem(jXKey);
                  if (null === jV) return -1;
                  const nV = jV.length;
                  if (nBuf <= 0) return nV;else if (1 === nBuf) {
                    wasm.poke(zBuf, 0);
                    return nV;
                  }
                  if (nBuf + 1 < nV) toss3(capi.SQLITE_RANGE, "xRcrdRead()", jzClass, jXKey, "input buffer is too small: need", nV, "but have", nBuf);
                  const zV = cache.memBuffer(0);
                  const heap = wasm.heap8();
                  let i;
                  for (i = 0; i < nV; ++i) heap[wasm.ptr.add(zV, i)] = jV.codePointAt(i) & 255;
                  heap.copyWithin(Number(zBuf), Number(zV), wasm.ptr.addn(zV, i));
                  heap[wasm.ptr.add(zBuf, nV)] = 0;
                  return nBuf;
                } catch (e) {
                  error("kvrecordRead()", e);
                  cache.setError(e);
                  return -2;
                }
              },
              xRcrdWrite: (zClass, zKey, zData) => {
                try {
                  const store = storageForZClass(zClass);
                  const jxKey = jsKeyForStorage(store, zClass, zKey);
                  const jData = wasm.cstrToJs(zData);
                  kvvfs?.log?.xRcrdWrite && warn("xRcrdWrite", jxKey, store);
                  store.storage.setItem(jxKey, jData);
                  store.listeners && notifyListeners("write", store, jxKey, jData);
                  return 0;
                } catch (e) {
                  error("kvrecordWrite()", e);
                  return cache.setError(e, capi.SQLITE_IOERR);
                }
              },
              xRcrdDelete: (zClass, zKey) => {
                try {
                  const store = storageForZClass(zClass);
                  const jxKey = jsKeyForStorage(store, zClass, zKey);
                  kvvfs?.log?.xRcrdDelete && warn("xRcrdDelete", jxKey, store);
                  store.storage.removeItem(jxKey);
                  store.listeners && notifyListeners("delete", store, jxKey);
                  return 0;
                } catch (e) {
                  error("kvrecordDelete()", e);
                  return cache.setError(e, capi.SQLITE_IOERR);
                }
              }
            },
            vfs: {
              xOpen: function (pProtoVfs, zName, pProtoFile, flags, pOutFlags) {
                cache.popError();
                let zToFree;
                try {
                  if (!zName) {
                    zToFree = wasm.allocCString("" + pProtoFile + "." + (Math.random() * 1e5 | 0));
                    zName = zToFree;
                  }
                  const jzClass = wasm.cstrToJs(zName);
                  kvvfs?.log?.xOpen && debug("xOpen", jzClass, "flags =", flags);
                  validateStorageName(jzClass, true);
                  if (flags & (capi.SQLITE_OPEN_MAIN_DB | capi.SQLITE_OPEN_TEMP_DB | capi.SQLITE_OPEN_TRANSIENT_DB) && cache.rxJournalSuffix.test(jzClass)) toss3(capi.SQLITE_ERROR, "DB files may not have a '-journal' suffix.");
                  let s = storageForZClass(jzClass);
                  if (!s && !(flags & capi.SQLITE_OPEN_CREATE)) toss3(capi.SQLITE_ERROR, "Storage not found:", jzClass);
                  const rc = originalMethods.vfs.xOpen(pProtoVfs, zName, pProtoFile, flags, pOutFlags);
                  if (rc) return rc;
                  let deleteAt0 = !!(capi.SQLITE_OPEN_DELETEONCLOSE & flags);
                  if (wasm.isPtr(arguments[1])) {
                    if (capi.sqlite3_uri_boolean(zName, "delete-on-close", 0)) deleteAt0 = true;
                  }
                  const f = new KVVfsFile(pProtoFile);
                  util.assert(f.$zClass, "Missing f.$zClass");
                  f.addOnDispose(zToFree);
                  zToFree = void 0;
                  if (s) {
                    ++s.refc;
                    s.files.push(f);
                    wasm.poke32(pOutFlags, flags);
                  } else {
                    wasm.poke32(pOutFlags, flags | capi.SQLITE_OPEN_CREATE);
                    util.assert(!f.$isJournal, "Opening a journal before its db? " + jzClass);
                    const nm = jzClass.replace(cache.rxJournalSuffix, "");
                    s = newStorageObj(nm);
                    installStorageAndJournal(s);
                    s.files.push(f);
                    s.deleteAtRefc0 = deleteAt0;
                    kvvfs?.log?.xOpen && debug("xOpen installed storage handle [", nm, nm + "-journal", "]", s);
                  }
                  pFileHandles.set(pProtoFile, {
                    store: s,
                    file: f,
                    jzClass
                  });
                  s.listeners && notifyListeners("open", s, s.files.length);
                  return 0;
                } catch (e) {
                  warn("xOpen:", e);
                  return cache.setError(e);
                } finally {
                  zToFree && wasm.dealloc(zToFree);
                }
              },
              xDelete: function (pVfs, zName, iSyncFlag) {
                cache.popError();
                try {
                  const jzName = wasm.cstrToJs(zName);
                  if (cache.rxJournalSuffix.test(jzName)) recordHandler.xRcrdDelete(zName, cache.zKeyJrnl);
                  return 0;
                } catch (e) {
                  warn("xDelete", e);
                  return cache.setError(e);
                }
              },
              xAccess: function (pProtoVfs, zPath, flags, pResOut) {
                cache.popError();
                try {
                  const s = storageForZClass(zPath);
                  const jzPath = s?.jzClass || wasm.cstrToJs(zPath);
                  if (kvvfs?.log?.xAccess) debug("xAccess", jzPath, "flags =", flags, "*pResOut =", wasm.peek32(pResOut), "store =", s);
                  if (!s) try {
                    validateStorageName(jzPath);
                  } catch (e) {
                    wasm.poke32(pResOut, 0);
                    return 0;
                  }
                  if (s) {
                    const key = s.keyPrefix + (cache.rxJournalSuffix.test(jzPath) ? "jrnl" : "1");
                    const res = s.storage.getItem(key) ? 0 : 1;
                    wasm.poke32(pResOut, res);
                  } else wasm.poke32(pResOut, 0);
                  return 0;
                } catch (e) {
                  error("xAccess", e);
                  return cache.setError(e);
                }
              },
              xRandomness: function (pVfs, nOut, pOut) {
                const heap = wasm.heap8u();
                let i = 0;
                const npOut = Number(pOut);
                for (; i < nOut; ++i) heap[npOut + i] = Math.random() * 255e3 & 255;
                return nOut;
              },
              xGetLastError: function (pVfs, nOut, pOut) {
                const e = cache.popError();
                debug("xGetLastError", e);
                if (e) {
                  const scope = wasm.scopedAllocPush();
                  try {
                    const [cMsg, n] = wasm.scopedAllocCString(e.message, true);
                    wasm.cstrncpy(pOut, cMsg, nOut);
                    if (n > nOut) wasm.poke8(wasm.ptr.add(pOut, nOut, -1), 0);
                    debug("set xGetLastError", e.message);
                    return e.resultCode | 0 || capi.SQLITE_IOERR;
                  } catch (e) {
                    return capi.SQLITE_NOMEM;
                  } finally {
                    wasm.scopedAllocPop(scope);
                  }
                }
                return 0;
              }
            },
            ioDb: {
              xClose: function (pFile) {
                cache.popError();
                try {
                  const h = pFileHandles.get(pFile);
                  kvvfs?.log?.xClose && debug("xClose", pFile, h);
                  if (h) {
                    pFileHandles.delete(pFile);
                    const s = h.store;
                    s.files = s.files.filter(v => v !== h.file);
                    if (--s.refc <= 0 && s.deleteAtRefc0) deleteStorage(s);
                    originalMethods.ioDb.xClose(pFile);
                    h.file.dispose();
                    s.listeners && notifyListeners("close", s, s.files.length);
                  }
                  return 0;
                } catch (e) {
                  error("xClose", e);
                  return cache.setError(e);
                }
              },
              xFileControl: function (pFile, opId, pArg) {
                cache.popError();
                try {
                  const h = pFileHandles.get(pFile);
                  util.assert(h, "Missing KVVfsFile handle");
                  kvvfs?.log?.xFileControl && debug("xFileControl", h, "op =", opId);
                  if (opId === capi.SQLITE_FCNTL_PRAGMA && kvvfsInternal.disablePageSizeChange) {
                    const zName = wasm.peekPtr(wasm.ptr.add(pArg, wasm.ptr.size));
                    if ("page_size" === wasm.cstrToJs(zName)) {
                      kvvfs?.log?.xFileControl && debug("xFileControl pragma", wasm.cstrToJs(zName));
                      const zVal = wasm.peekPtr(wasm.ptr.add(pArg, 2 * wasm.ptr.size));
                      if (zVal) {
                        kvvfs?.log?.xFileControl && warn("xFileControl pragma", h, "NOT setting page size to", wasm.cstrToJs(zVal));
                        h.file.$szPage = -1;
                        return 0;
                      } else if (h.file.$szPage > 0) {
                        kvvfs?.log?.xFileControl && warn("xFileControl", h, "getting page size", h.file.$szPage);
                        wasm.pokePtr(pArg, wasm.allocCString("" + h.file.$szPage));
                        return 0;
                      }
                    }
                  }
                  const rc = originalMethods.ioDb.xFileControl(pFile, opId, pArg);
                  if (0 == rc && capi.SQLITE_FCNTL_SYNC === opId) h.store.listeners && notifyListeners("sync", h.store, false);
                  return rc;
                } catch (e) {
                  error("xFileControl", e);
                  return cache.setError(e);
                }
              },
              xSync: function (pFile, flags) {
                cache.popError();
                try {
                  const h = pFileHandles.get(pFile);
                  kvvfs?.log?.xSync && debug("xSync", h);
                  util.assert(h, "Missing KVVfsFile handle");
                  const rc = originalMethods.ioDb.xSync(pFile, flags);
                  if (0 == rc && h.store.listeners) notifyListeners("sync", h.store, true);
                  return rc;
                } catch (e) {
                  error("xSync", e);
                  return cache.setError(e);
                }
              },
              xRead: function (pFile, pTgt, n, iOff64) {
                cache.popError();
                try {
                  if (kvvfs?.log?.xRead) {
                    const h = pFileHandles.get(pFile);
                    util.assert(h, "Missing KVVfsFile handle");
                    debug("xRead", n, iOff64, h);
                  }
                  return originalMethods.ioDb.xRead(pFile, pTgt, n, iOff64);
                } catch (e) {
                  error("xRead", e);
                  return cache.setError(e);
                }
              },
              xWrite: function (pFile, pSrc, n, iOff64) {
                cache.popError();
                try {
                  if (kvvfs?.log?.xWrite) {
                    const h = pFileHandles.get(pFile);
                    util.assert(h, "Missing KVVfsFile handle");
                    debug("xWrite", n, iOff64, h);
                  }
                  return originalMethods.ioDb.xWrite(pFile, pSrc, n, iOff64);
                } catch (e) {
                  error("xWrite", e);
                  return cache.setError(e);
                }
              }
            },
            ioJrnl: {
              xClose: true
            }
          };
          debug("pVfs and friends", pVfs, pIoDb, pIoJrnl, kvvfsMethods, capi.sqlite3_file.structInfo, KVVfsFile.structInfo);
          try {
            util.assert(cache.buffer.n > 1024 * 129, "Heap buffer is not large enough");
            for (const e of Object.entries(methodOverrides.recordHandler)) {
              const k = e[0],
                f = e[1];
              recordHandler[k] = f;
              kvvfsMethods[kvvfsMethods.memberKey(k)] = wasm.installFunction(kvvfsMethods.memberSignature(k), f);
            }
            for (const e of Object.entries(methodOverrides.vfs)) {
              const k = e[0],
                f = e[1],
                km = pVfs.memberKey(k),
                member = pVfs.structInfo.members[k] || util.toss("Missing pVfs.structInfo[", k, "]");
              originalMethods.vfs[k] = wasm.functionEntry(pVfs[km]);
              pVfs[km] = wasm.installFunction(member.signature, f);
            }
            for (const e of Object.entries(methodOverrides.ioDb)) {
              const k = e[0],
                f = e[1],
                km = pIoDb.memberKey(k);
              originalMethods.ioDb[k] = wasm.functionEntry(pIoDb[km]) || util.toss("Missing native pIoDb[", km, "]");
              pIoDb[km] = wasm.installFunction(pIoDb.memberSignature(k), f);
            }
            for (const e of Object.entries(methodOverrides.ioJrnl)) {
              const k = e[0],
                f = e[1],
                km = pIoJrnl.memberKey(k);
              originalMethods.ioJrnl[k] = wasm.functionEntry(pIoJrnl[km]) || util.toss("Missing native pIoJrnl[", km, "]");
              if (true === f) pIoJrnl[km] = pIoDb[km] || util.toss("Missing copied pIoDb[", km, "]");else pIoJrnl[km] = wasm.installFunction(pIoJrnl.memberSignature(k), f);
            }
          } finally {
            kvvfsMethods.dispose();
            pVfs.dispose();
            pIoDb.dispose();
            pIoJrnl.dispose();
          }
          const sqlite3_js_kvvfs_clear = function callee(which) {
            if ("" === which) return callee("local") + callee("session");
            const store = storageForZClass(which);
            if (!store) return 0;
            if (store.files.length) if (globalThis.localStorage === store.storage || globalThis.sessionStorage === store.storage) ; else toss3(capi.SQLITE_ACCESS, "Cannot clear in-use database storage.");
            const s = store.storage;
            const toRm = [];
            let i,
              n = s.length;
            for (i = 0; i < n; ++i) {
              const k = s.key(i);
              if (!store.keyPrefix || k.startsWith(store.keyPrefix)) toRm.push(k);
            }
            toRm.forEach(kk => s.removeItem(kk));
            return toRm.length;
          };
          const sqlite3_js_kvvfs_size = function callee(which) {
            if ("" === which) return callee("local") + callee("session");
            const store = storageForZClass(which);
            if (!store) return 0;
            const s = store.storage;
            let i,
              sz = 0;
            for (i = 0; i < s.length; ++i) {
              const k = s.key(i);
              if (!store.keyPrefix || k.startsWith(store.keyPrefix)) {
                sz += k.length;
                sz += s.getItem(k).length;
              }
            }
            return sz * 2;
          };
          const sqlite3_js_kvvfs_export = function callee(...args) {
            let opt;
            if (1 === args.length && "object" === typeof args[0]) opt = args[0];else if (args.length) opt = Object.assign(Object.create(null), {
              name: args[0]
            });
            const store = opt ? storageForZClass(opt.name) : null;
            if (!store) toss3(capi.SQLITE_NOTFOUND, "There is no kvvfs storage named", opt?.name);
            const s = store.storage;
            const rc = Object.assign(Object.create(null), {
              name: store.jzClass,
              timestamp: Date.now(),
              pages: []
            });
            const pages = Object.create(null);
            const keyPrefix = store.keyPrefix;
            const rxTail = keyPrefix ? /^kvvfs-[^-]+-(\w+)/ : void 0;
            let i = 0,
              n = s.length;
            for (; i < n; ++i) {
              const k = s.key(i);
              if (!keyPrefix || k.startsWith(keyPrefix)) {
                let kk = (keyPrefix ? rxTail.exec(k) : void 0)?.[1] ?? k;
                switch (kk) {
                  case "jrnl":
                    if (opt.includeJournal) rc.journal = s.getItem(k);
                    break;
                  case "sz":
                    rc.size = +s.getItem(k);
                    break;
                  default:
                    kk = +kk;
                    if (!util.isInt32(kk) || kk <= 0) toss3(capi.SQLITE_RANGE, "Malformed kvvfs key: " + k);
                    if (opt.decodePages) {
                      const spg = s.getItem(k),
                        n = spg.length,
                        z = cache.memBuffer(0),
                        zDec = cache.memBuffer(1),
                        heap = wasm.heap8u();
                      let i = 0;
                      for (; i < n; ++i) heap[wasm.ptr.add(z, i)] = spg.codePointAt(i) & 255;
                      heap[wasm.ptr.add(z, i)] = 0;
                      const nDec = kvvfsDecode(z, zDec, cache.buffer.n);
                      pages[kk] = heap.slice(Number(zDec), wasm.ptr.addn(zDec, nDec));
                    } else pages[kk] = s.getItem(k);
                    break;
                }
              }
            }
            if (opt.decodePages) cache.memBufferFree(1);
            Object.keys(pages).map(v => +v).sort().forEach(v => rc.pages.push(pages[v]));
            return rc;
          };
          const sqlite3_js_kvvfs_import = function (exp, overwrite = false) {
            if (!exp?.timestamp || !exp.name || void 0 === exp.size || !Array.isArray(exp.pages)) toss3(capi.SQLITE_MISUSE, "Malformed export object.");else if (!exp.size || exp.size !== (exp.size | 0) || exp.size >= 2147483647) toss3(capi.SQLITE_RANGE, "Invalid db size: " + exp.size);
            validateStorageName(exp.name);
            let store = storageForZClass(exp.name);
            const isNew = !store;
            if (store) {
              if (!overwrite) toss3(capi.SQLITE_ACCESS, "Storage '" + exp.name + "' already exists and", "overwrite was not specified.");else if (!store.files || !store.jzClass) toss3(capi.SQLITE_ERROR, "Internal storage object", exp.name, "seems to be malformed.");else if (store.files.length) toss3(capi.SQLITE_IOERR_ACCESS, "Cannot import db storage while it is in use.");
              sqlite3_js_kvvfs_clear(exp.name);
            } else store = newStorageObj(exp.name);
            const keyPrefix = kvvfsKeyPrefix(exp.name);
            let zEnc;
            try {
              const s = store.storage;
              s.setItem(keyPrefix + "sz", exp.size);
              if (exp.journal) s.setItem(keyPrefix + "jrnl", exp.journal);
              if (exp.pages[0] instanceof Uint8Array) exp.pages.forEach((u, ndx) => {
                const n = u.length;
                zEnc ??= cache.memBuffer(1);
                const zBin = cache.memBuffer(0),
                  heap = wasm.heap8u();
                heap.set(u, Number(zBin));
                heap[wasm.ptr.addn(zBin, n)] = 0;
                const rc = kvvfsEncode(zBin, n, zEnc);
                util.assert(rc < cache.buffer.n, "Impossibly long output - possibly smashed the heap");
                util.assert(0 === wasm.peek8(wasm.ptr.add(zEnc, rc)), "Expecting NUL-terminated encoded output");
                const jenc = wasm.cstrToJs(zEnc);
                s.setItem(keyPrefix + (ndx + 1), jenc);
              });else if (exp.pages[0]) exp.pages.forEach((v, ndx) => s.setItem(keyPrefix + (ndx + 1), v));
              if (isNew) installStorageAndJournal(store);
            } catch {
              if (!isNew) try {
                sqlite3_js_kvvfs_clear(exp.name);
              } catch (ee) {}
            } finally {
              if (zEnc) cache.memBufferFree(1);
            }
            return this;
          };
          const sqlite3_js_kvvfs_reserve = function (name) {
            let store = storageForZClass(name);
            if (store) {
              ++store.refc;
              return;
            }
            validateStorageName(name);
            installStorageAndJournal(newStorageObj(name));
          };
          const sqlite3_js_kvvfs_unlink = function (name) {
            const store = storageForZClass(name);
            if (!store || kvvfsIsPersistentName(store.jzClass) || isBuiltinName(store.jzClass) || cache.rxJournalSuffix.test(name)) return false;
            if (store.refc > store.files.length || 0 === store.files.length) {
              if (--store.refc <= 0) deleteStorage(store);
              return true;
            }
            return false;
          };
          const sqlite3_js_kvvfs_listen = function (opt) {
            if (!opt || "object" !== typeof opt) toss3(capi.SQLITE_MISUSE, "Expecting a listener object.");
            let store = storageForZClass(opt.storage);
            if (!store) if (opt.storage && opt.reserve) {
              sqlite3_js_kvvfs_reserve(opt.storage);
              store = storageForZClass(opt.storage);
              util.assert(store, "Unexpectedly cannot fetch reserved storage " + opt.storage);
            } else toss3(capi.SQLITE_NOTFOUND, "No such storage:", opt.storage);
            if (opt.events) (store.listeners ??= []).push(opt);
          };
          const sqlite3_js_kvvfs_unlisten = function (opt) {
            const store = storageForZClass(opt?.storage);
            if (store?.listeners && opt.events) {
              const n = store.listeners.length;
              store.listeners = store.listeners.filter(v => v !== opt);
              const rc = n > store.listeners.length;
              if (!store.listeners.length) store.listeners = void 0;
              return rc;
            }
            return false;
          };
          sqlite3.kvvfs.reserve = sqlite3_js_kvvfs_reserve;
          sqlite3.kvvfs.import = sqlite3_js_kvvfs_import;
          sqlite3.kvvfs.export = sqlite3_js_kvvfs_export;
          sqlite3.kvvfs.unlink = sqlite3_js_kvvfs_unlink;
          sqlite3.kvvfs.listen = sqlite3_js_kvvfs_listen;
          sqlite3.kvvfs.unlisten = sqlite3_js_kvvfs_unlisten;
          sqlite3.kvvfs.exists = name => !!storageForZClass(name);
          sqlite3.kvvfs.estimateSize = sqlite3_js_kvvfs_size;
          sqlite3.kvvfs.clear = sqlite3_js_kvvfs_clear;
          if (globalThis.Storage) {
            capi.sqlite3_js_kvvfs_size = (which = "") => sqlite3_js_kvvfs_size(which);
            capi.sqlite3_js_kvvfs_clear = (which = "") => sqlite3_js_kvvfs_clear(which);
          }
          if (sqlite3.oo1?.DB) {
            const DB = sqlite3.oo1.DB;
            sqlite3.oo1.JsStorageDb = function (storageName = sqlite3.oo1.JsStorageDb.defaultStorageName) {
              const opt = DB.dbCtorHelper.normalizeArgs(...arguments);
              opt.vfs = "kvvfs";
              switch (opt.filename) {
                case ":sessionStorage:":
                  opt.filename = "session";
                  break;
                case ":localStorage:":
                  opt.filename = "local";
                  break;
              }
              const m = /(file:(\/\/)?)([^?]+)/.exec(opt.filename);
              validateStorageName(m ? m[3] : opt.filename);
              DB.dbCtorHelper.call(this, opt);
            };
            sqlite3.oo1.JsStorageDb.defaultStorageName = cache.storagePool.session ? "session" : nameOfThisThreadStorage;
            const jdb = sqlite3.oo1.JsStorageDb;
            jdb.prototype = Object.create(DB.prototype);
            jdb.clearStorage = sqlite3_js_kvvfs_clear;
            jdb.prototype.clearStorage = function () {
              return jdb.clearStorage(this.affirmOpen().dbFilename(), true);
            };
            jdb.storageSize = sqlite3_js_kvvfs_size;
            jdb.prototype.storageSize = function () {
              return jdb.storageSize(this.affirmOpen().dbFilename(), true);
            };
          }
          if (sqlite3.__isUnderTest && sqlite3.vtab) {
            const cols = Object.assign(Object.create(null), {
              rowid: {
                type: "INTEGER"
              },
              name: {
                type: "TEXT"
              },
              nRef: {
                type: "INTEGER"
              },
              nOpen: {
                type: "INTEGER"
              },
              isTransient: {
                type: "INTEGER"
              },
              dbSize: {
                type: "INTEGER"
              }
            });
            Object.keys(cols).forEach((v, i) => cols[v].colId = i);
            const VT = sqlite3.vtab;
            const ProtoCursor = Object.assign(Object.create(null), {
              row: function () {
                return cache.storagePool[this.names[this.rowid]];
              }
            });
            Object.assign(Object.create(ProtoCursor), {
              rowid: 0,
              names: Object.keys(cache.storagePool).filter(v => !cache.rxJournalSuffix.test(v))
            });
            const cursorState = function (cursor, reset) {
              const o = cursor instanceof capi.sqlite3_vtab_cursor ? cursor : VT.xCursor.get(cursor);
              if (reset || !o.vTabState) o.vTabState = Object.assign(Object.create(ProtoCursor), {
                rowid: 0,
                names: Object.keys(cache.storagePool).filter(v => !cache.rxJournalSuffix.test(v))
              });
              return o.vTabState;
            };
            const dbg = () => {};
            const theModule = function f() {
              return f.mod ??= new sqlite3.capi.sqlite3_module().setupModule({
                catchExceptions: true,
                methods: {
                  xConnect: function (pDb, pAux, argc, argv, ppVtab, pzErr) {
                    try {
                      const xcol = [];
                      Object.keys(cols).forEach(k => {
                        xcol.push(k + " " + cols[k].type);
                      });
                      const rc = capi.sqlite3_declare_vtab(pDb, "CREATE TABLE ignored(" + xcol.join(",") + ")");
                      if (0 === rc) {
                        const t = VT.xVtab.create(ppVtab);
                        util.assert(t === VT.xVtab.get(wasm.peekPtr(ppVtab)), "output pointer check failed");
                      }
                      return rc;
                    } catch (e) {
                      return VT.xErrror("xConnect", e, capi.SQLITE_ERROR);
                    }
                  },
                  xCreate: wasm.ptr.null,
                  xDisconnect: function (pVtab) {
                    VT.xVtab.dispose(pVtab);
                    return 0;
                  },
                  xOpen: function (pVtab, ppCursor) {
                    VT.xCursor.create(ppCursor);
                    return 0;
                  },
                  xClose: function (pCursor) {
                    const c = VT.xCursor.unget(pCursor);
                    delete c.vTabState;
                    c.dispose();
                    return 0;
                  },
                  xNext: function (pCursor) {
                    const c = VT.xCursor.get(pCursor);
                    ++cursorState(c).rowid;
                    return 0;
                  },
                  xColumn: function (pCursor, pCtx, iCol) {
                    const st = cursorState(pCursor);
                    const store = st.row();
                    util.assert(store, "Unexpected xColumn call");
                    switch (iCol) {
                      case cols.rowid.colId:
                        capi.sqlite3_result_int(pCtx, st.rowid);
                        break;
                      case cols.name.colId:
                        capi.sqlite3_result_text(pCtx, store.jzClass, -1, capi.SQLITE_TRANSIENT);
                        break;
                      case cols.nRef.colId:
                        capi.sqlite3_result_int(pCtx, store.refc);
                        break;
                      case cols.nOpen.colId:
                        capi.sqlite3_result_int(pCtx, store.files.length);
                        break;
                      case cols.isTransient.colId:
                        capi.sqlite3_result_int(pCtx, !!store.deleteAtRefc0);
                        break;
                      case cols.dbSize.colId:
                        capi.sqlite3_result_int(pCtx, storageGetDbSize(store));
                        break;
                      default:
                        capi.sqlite3_result_error(pCtx, "Invalid column id: " + iCol);
                        return capi.SQLITE_RANGE;
                    }
                    return 0;
                  },
                  xRowid: function (pCursor, ppRowid64) {
                    const st = cursorState(pCursor);
                    VT.xRowid(ppRowid64, st.rowid);
                    return 0;
                  },
                  xEof: function (pCursor) {
                    const st = cursorState(pCursor);
                    dbg("xEof?=" + !st.row(), ...arguments);
                    return !st.row();
                  },
                  xFilter: function (pCursor, idxNum, idxCStr, argc, argv) {
                    cursorState(pCursor, true);
                    return 0;
                  },
                  xBestIndex: function (pVtab, pIdxInfo) {
                    const pii = new capi.sqlite3_index_info(pIdxInfo);
                    pii.$estimatedRows = cache.storagePool.size;
                    pii.$estimatedCost = 1;
                    pii.dispose();
                    return 0;
                  }
                }
              });
            };
            sqlite3.kvvfs.create_module = function (pDb, name = "sqlite_kvvfs") {
              return capi.sqlite3_create_module(pDb, name, theModule(), wasm.ptr.null);
            };
          }
        });
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {
          const installOpfsVfs = function callee(options) {
            if (!globalThis.SharedArrayBuffer || !globalThis.Atomics) return Promise.reject(/* @__PURE__ */new Error("Cannot install OPFS: Missing SharedArrayBuffer and/or Atomics. The server must emit the COOP/COEP response headers to enable those. See https://sqlite.org/wasm/doc/trunk/persistence.md#coop-coep"));else if ("undefined" === typeof WorkerGlobalScope) return Promise.reject(/* @__PURE__ */new Error("The OPFS sqlite3_vfs cannot run in the main thread because it requires Atomics.wait()."));else if (!globalThis.FileSystemHandle || !globalThis.FileSystemDirectoryHandle || !globalThis.FileSystemFileHandle || !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || !navigator?.storage?.getDirectory) return Promise.reject(/* @__PURE__ */new Error("Missing required OPFS APIs."));
            if (!options || "object" !== typeof options) options = Object.create(null);
            const urlParams = new URL(globalThis.location.href).searchParams;
            if (urlParams.has("opfs-disable")) return Promise.resolve(sqlite3);
            if (void 0 === options.verbose) options.verbose = urlParams.has("opfs-verbose") ? +urlParams.get("opfs-verbose") || 2 : 1;
            if (void 0 === options.sanityChecks) options.sanityChecks = urlParams.has("opfs-sanity-check");
            if (void 0 === options.proxyUri) options.proxyUri = callee.defaultProxyUri;
            if ("function" === typeof options.proxyUri) options.proxyUri = options.proxyUri();
            return new Promise(function (promiseResolve_, promiseReject_) {
              const loggers = [sqlite3.config.error, sqlite3.config.warn, sqlite3.config.log];
              const logImpl = (level, ...args) => {
                if (options.verbose > level) loggers[level]("OPFS syncer:", ...args);
              };
              const log = (...args) => logImpl(2, ...args);
              const warn = (...args) => logImpl(1, ...args);
              const error = (...args) => logImpl(0, ...args);
              const toss = sqlite3.util.toss;
              const capi = sqlite3.capi;
              const util = sqlite3.util;
              const wasm = sqlite3.wasm;
              const sqlite3_vfs = capi.sqlite3_vfs;
              const sqlite3_file = capi.sqlite3_file;
              const sqlite3_io_methods = capi.sqlite3_io_methods;
              const opfsUtil = Object.create(null);
              const thisThreadHasOPFS = () => {
                return globalThis.FileSystemHandle && globalThis.FileSystemDirectoryHandle && globalThis.FileSystemFileHandle && globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle && navigator?.storage?.getDirectory;
              };
              opfsUtil.metrics = {
                dump: function () {
                  let k,
                    n = 0,
                    t = 0,
                    w = 0;
                  for (k in state.opIds) {
                    const m = metrics[k];
                    n += m.count;
                    t += m.time;
                    w += m.wait;
                    m.avgTime = m.count && m.time ? m.time / m.count : 0;
                    m.avgWait = m.count && m.wait ? m.wait / m.count : 0;
                  }
                  sqlite3.config.log(globalThis.location.href, "metrics for", globalThis.location.href, ":", metrics, "\nTotal of", n, "op(s) for", t, "ms (incl. " + w + " ms of waiting on the async side)");
                  sqlite3.config.log("Serialization metrics:", metrics.s11n);
                  W.postMessage({
                    type: "opfs-async-metrics"
                  });
                },
                reset: function () {
                  let k;
                  const r = m => m.count = m.time = m.wait = 0;
                  for (k in state.opIds) r(metrics[k] = Object.create(null));
                  let s = metrics.s11n = Object.create(null);
                  s = s.serialize = Object.create(null);
                  s.count = s.time = 0;
                  s = metrics.s11n.deserialize = Object.create(null);
                  s.count = s.time = 0;
                }
              };
              const opfsIoMethods = new sqlite3_io_methods();
              const opfsVfs = new sqlite3_vfs().addOnDispose(() => opfsIoMethods.dispose());
              let promiseWasRejected = void 0;
              const promiseReject = err => {
                promiseWasRejected = true;
                opfsVfs.dispose();
                return promiseReject_(err);
              };
              const promiseResolve = () => {
                promiseWasRejected = false;
                return promiseResolve_(sqlite3);
              };
              const W = new Worker(new URL("sqlite3-opfs-async-proxy.js", (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('dls-analysis.umd.js', document.baseURI).href))));
              setTimeout(() => {
                if (void 0 === promiseWasRejected) promiseReject(/* @__PURE__ */new Error("Timeout while waiting for OPFS async proxy worker."));
              }, 4e3);
              W._originalOnError = W.onerror;
              W.onerror = function (err) {
                error("Error initializing OPFS asyncer:", err);
                promiseReject(/* @__PURE__ */new Error("Loading OPFS async Worker failed for unknown reasons."));
              };
              const pDVfs = capi.sqlite3_vfs_find(null);
              const dVfs = pDVfs ? new sqlite3_vfs(pDVfs) : null;
              opfsIoMethods.$iVersion = 1;
              opfsVfs.$iVersion = 2;
              opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
              opfsVfs.$mxPathname = 1024;
              opfsVfs.$zName = wasm.allocCString("opfs");
              opfsVfs.$xDlOpen = opfsVfs.$xDlError = opfsVfs.$xDlSym = opfsVfs.$xDlClose = null;
              opfsVfs.addOnDispose("$zName", opfsVfs.$zName, "cleanup default VFS wrapper", () => dVfs ? dVfs.dispose() : null);
              const state = Object.create(null);
              state.verbose = options.verbose;
              state.littleEndian = (() => {
                const buffer = /* @__PURE__ */new ArrayBuffer(2);
                new DataView(buffer).setInt16(0, 256, true);
                return new Int16Array(buffer)[0] === 256;
              })();
              state.asyncIdleWaitTime = 150;
              state.asyncS11nExceptions = 1;
              state.fileBufferSize = 1024 * 64;
              state.sabS11nOffset = state.fileBufferSize;
              state.sabS11nSize = opfsVfs.$mxPathname * 2;
              state.sabIO = new SharedArrayBuffer(state.fileBufferSize + state.sabS11nSize);
              state.opIds = Object.create(null);
              const metrics = Object.create(null);
              {
                let i = 0;
                state.opIds.whichOp = i++;
                state.opIds.rc = i++;
                state.opIds.xAccess = i++;
                state.opIds.xClose = i++;
                state.opIds.xDelete = i++;
                state.opIds.xDeleteNoWait = i++;
                state.opIds.xFileSize = i++;
                state.opIds.xLock = i++;
                state.opIds.xOpen = i++;
                state.opIds.xRead = i++;
                state.opIds.xSleep = i++;
                state.opIds.xSync = i++;
                state.opIds.xTruncate = i++;
                state.opIds.xUnlock = i++;
                state.opIds.xWrite = i++;
                state.opIds.mkdir = i++;
                state.opIds["opfs-async-metrics"] = i++;
                state.opIds["opfs-async-shutdown"] = i++;
                state.opIds.retry = i++;
                state.sabOP = new SharedArrayBuffer(i * 4);
                opfsUtil.metrics.reset();
              }
              state.sq3Codes = Object.create(null);
              ["SQLITE_ACCESS_EXISTS", "SQLITE_ACCESS_READWRITE", "SQLITE_BUSY", "SQLITE_CANTOPEN", "SQLITE_ERROR", "SQLITE_IOERR", "SQLITE_IOERR_ACCESS", "SQLITE_IOERR_CLOSE", "SQLITE_IOERR_DELETE", "SQLITE_IOERR_FSYNC", "SQLITE_IOERR_LOCK", "SQLITE_IOERR_READ", "SQLITE_IOERR_SHORT_READ", "SQLITE_IOERR_TRUNCATE", "SQLITE_IOERR_UNLOCK", "SQLITE_IOERR_WRITE", "SQLITE_LOCK_EXCLUSIVE", "SQLITE_LOCK_NONE", "SQLITE_LOCK_PENDING", "SQLITE_LOCK_RESERVED", "SQLITE_LOCK_SHARED", "SQLITE_LOCKED", "SQLITE_MISUSE", "SQLITE_NOTFOUND", "SQLITE_OPEN_CREATE", "SQLITE_OPEN_DELETEONCLOSE", "SQLITE_OPEN_MAIN_DB", "SQLITE_OPEN_READONLY"].forEach(k => {
                if (void 0 === (state.sq3Codes[k] = capi[k])) toss("Maintenance required: not found:", k);
              });
              state.opfsFlags = Object.assign(Object.create(null), {
                OPFS_UNLOCK_ASAP: 1,
                OPFS_UNLINK_BEFORE_OPEN: 2,
                defaultUnlockAsap: false
              });
              const opRun = (op, ...args) => {
                const opNdx = state.opIds[op] || toss("Invalid op ID:", op);
                state.s11n.serialize(...args);
                Atomics.store(state.sabOPView, state.opIds.rc, -1);
                Atomics.store(state.sabOPView, state.opIds.whichOp, opNdx);
                Atomics.notify(state.sabOPView, state.opIds.whichOp);
                const t = performance.now();
                while ("not-equal" !== Atomics.wait(state.sabOPView, state.opIds.rc, -1));
                const rc = Atomics.load(state.sabOPView, state.opIds.rc);
                metrics[op].wait += performance.now() - t;
                if (rc && state.asyncS11nExceptions) {
                  const err = state.s11n.deserialize();
                  if (err) error(op + "() async error:", ...err);
                }
                return rc;
              };
              opfsUtil.debug = {
                asyncShutdown: () => {
                  warn("Shutting down OPFS async listener. The OPFS VFS will no longer work.");
                  opRun("opfs-async-shutdown");
                },
                asyncRestart: () => {
                  warn("Attempting to restart OPFS VFS async listener. Might work, might not.");
                  W.postMessage({
                    type: "opfs-async-restart"
                  });
                }
              };
              const initS11n = () => {
                if (state.s11n) return state.s11n;
                const textDecoder = new TextDecoder(),
                  textEncoder = new TextEncoder("utf-8"),
                  viewU8 = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize),
                  viewDV = new DataView(state.sabIO, state.sabS11nOffset, state.sabS11nSize);
                state.s11n = Object.create(null);
                const TypeIds = Object.create(null);
                TypeIds.number = {
                  id: 1,
                  size: 8,
                  getter: "getFloat64",
                  setter: "setFloat64"
                };
                TypeIds.bigint = {
                  id: 2,
                  size: 8,
                  getter: "getBigInt64",
                  setter: "setBigInt64"
                };
                TypeIds.boolean = {
                  id: 3,
                  size: 4,
                  getter: "getInt32",
                  setter: "setInt32"
                };
                TypeIds.string = {
                  id: 4
                };
                const getTypeId = v => TypeIds[typeof v] || toss("Maintenance required: this value type cannot be serialized.", v);
                const getTypeIdById = tid => {
                  switch (tid) {
                    case TypeIds.number.id:
                      return TypeIds.number;
                    case TypeIds.bigint.id:
                      return TypeIds.bigint;
                    case TypeIds.boolean.id:
                      return TypeIds.boolean;
                    case TypeIds.string.id:
                      return TypeIds.string;
                    default:
                      toss("Invalid type ID:", tid);
                  }
                };
                state.s11n.deserialize = function (clear = false) {
                  ++metrics.s11n.deserialize.count;
                  const t = performance.now();
                  const argc = viewU8[0];
                  const rc = argc ? [] : null;
                  if (argc) {
                    const typeIds = [];
                    let offset = 1,
                      i,
                      n,
                      v;
                    for (i = 0; i < argc; ++i, ++offset) typeIds.push(getTypeIdById(viewU8[offset]));
                    for (i = 0; i < argc; ++i) {
                      const t = typeIds[i];
                      if (t.getter) {
                        v = viewDV[t.getter](offset, state.littleEndian);
                        offset += t.size;
                      } else {
                        n = viewDV.getInt32(offset, state.littleEndian);
                        offset += 4;
                        v = textDecoder.decode(viewU8.slice(offset, offset + n));
                        offset += n;
                      }
                      rc.push(v);
                    }
                  }
                  if (clear) viewU8[0] = 0;
                  metrics.s11n.deserialize.time += performance.now() - t;
                  return rc;
                };
                state.s11n.serialize = function (...args) {
                  const t = performance.now();
                  ++metrics.s11n.serialize.count;
                  if (args.length) {
                    const typeIds = [];
                    let i = 0,
                      offset = 1;
                    viewU8[0] = args.length & 255;
                    for (; i < args.length; ++i, ++offset) {
                      typeIds.push(getTypeId(args[i]));
                      viewU8[offset] = typeIds[i].id;
                    }
                    for (i = 0; i < args.length; ++i) {
                      const t = typeIds[i];
                      if (t.setter) {
                        viewDV[t.setter](offset, args[i], state.littleEndian);
                        offset += t.size;
                      } else {
                        const s = textEncoder.encode(args[i]);
                        viewDV.setInt32(offset, s.byteLength, state.littleEndian);
                        offset += 4;
                        viewU8.set(s, offset);
                        offset += s.byteLength;
                      }
                    }
                  } else viewU8[0] = 0;
                  metrics.s11n.serialize.time += performance.now() - t;
                };
                return state.s11n;
              };
              const randomFilename = function f(len = 16) {
                if (!f._chars) {
                  f._chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012346789";
                  f._n = f._chars.length;
                }
                const a = [];
                let i = 0;
                for (; i < len; ++i) {
                  const ndx = Math.random() * (f._n * 64) % f._n | 0;
                  a[i] = f._chars[ndx];
                }
                return a.join("");
              };
              const __openFiles = Object.create(null);
              const opTimer = Object.create(null);
              opTimer.op = void 0;
              opTimer.start = void 0;
              const mTimeStart = op => {
                opTimer.start = performance.now();
                opTimer.op = op;
                ++metrics[op].count;
              };
              const mTimeEnd = () => metrics[opTimer.op].time += performance.now() - opTimer.start;
              const ioSyncWrappers = {
                xCheckReservedLock: function (pFile, pOut) {
                  wasm.poke(pOut, 0, "i32");
                  return 0;
                },
                xClose: function (pFile) {
                  mTimeStart("xClose");
                  let rc = 0;
                  const f = __openFiles[pFile];
                  if (f) {
                    delete __openFiles[pFile];
                    rc = opRun("xClose", pFile);
                    if (f.sq3File) f.sq3File.dispose();
                  }
                  mTimeEnd();
                  return rc;
                },
                xDeviceCharacteristics: function (pFile) {
                  return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
                },
                xFileControl: function (pFile, opId, pArg) {
                  return capi.SQLITE_NOTFOUND;
                },
                xFileSize: function (pFile, pSz64) {
                  mTimeStart("xFileSize");
                  let rc = opRun("xFileSize", pFile);
                  if (0 == rc) try {
                    const sz = state.s11n.deserialize()[0];
                    wasm.poke(pSz64, sz, "i64");
                  } catch (e) {
                    error("Unexpected error reading xFileSize() result:", e);
                    rc = state.sq3Codes.SQLITE_IOERR;
                  }
                  mTimeEnd();
                  return rc;
                },
                xLock: function (pFile, lockType) {
                  mTimeStart("xLock");
                  const f = __openFiles[pFile];
                  let rc = 0;
                  if (!f.lockType) {
                    rc = opRun("xLock", pFile, lockType);
                    if (0 === rc) f.lockType = lockType;
                  } else f.lockType = lockType;
                  mTimeEnd();
                  return rc;
                },
                xRead: function (pFile, pDest, n, offset64) {
                  mTimeStart("xRead");
                  const f = __openFiles[pFile];
                  let rc;
                  try {
                    rc = opRun("xRead", pFile, n, Number(offset64));
                    if (0 === rc || capi.SQLITE_IOERR_SHORT_READ === rc) wasm.heap8u().set(f.sabView.subarray(0, n), Number(pDest));
                  } catch (e) {
                    error("xRead(", arguments, ") failed:", e, f);
                    rc = capi.SQLITE_IOERR_READ;
                  }
                  mTimeEnd();
                  return rc;
                },
                xSync: function (pFile, flags) {
                  mTimeStart("xSync");
                  ++metrics.xSync.count;
                  const rc = opRun("xSync", pFile, flags);
                  mTimeEnd();
                  return rc;
                },
                xTruncate: function (pFile, sz64) {
                  mTimeStart("xTruncate");
                  const rc = opRun("xTruncate", pFile, Number(sz64));
                  mTimeEnd();
                  return rc;
                },
                xUnlock: function (pFile, lockType) {
                  mTimeStart("xUnlock");
                  const f = __openFiles[pFile];
                  let rc = 0;
                  if (capi.SQLITE_LOCK_NONE === lockType && f.lockType) rc = opRun("xUnlock", pFile, lockType);
                  if (0 === rc) f.lockType = lockType;
                  mTimeEnd();
                  return rc;
                },
                xWrite: function (pFile, pSrc, n, offset64) {
                  mTimeStart("xWrite");
                  const f = __openFiles[pFile];
                  let rc;
                  try {
                    f.sabView.set(wasm.heap8u().subarray(Number(pSrc), Number(pSrc) + n));
                    rc = opRun("xWrite", pFile, n, Number(offset64));
                  } catch (e) {
                    error("xWrite(", arguments, ") failed:", e, f);
                    rc = capi.SQLITE_IOERR_WRITE;
                  }
                  mTimeEnd();
                  return rc;
                }
              };
              const vfsSyncWrappers = {
                xAccess: function (pVfs, zName, flags, pOut) {
                  mTimeStart("xAccess");
                  const rc = opRun("xAccess", wasm.cstrToJs(zName));
                  wasm.poke(pOut, rc ? 0 : 1, "i32");
                  mTimeEnd();
                  return 0;
                },
                xCurrentTime: function (pVfs, pOut) {
                  wasm.poke(pOut, 2440587.5 + (/* @__PURE__ */new Date()).getTime() / 864e5, "double");
                  return 0;
                },
                xCurrentTimeInt64: function (pVfs, pOut) {
                  wasm.poke(pOut, 2440587.5 * 864e5 + (/* @__PURE__ */new Date()).getTime(), "i64");
                  return 0;
                },
                xDelete: function (pVfs, zName, doSyncDir) {
                  mTimeStart("xDelete");
                  const rc = opRun("xDelete", wasm.cstrToJs(zName), doSyncDir, false);
                  mTimeEnd();
                  return rc;
                },
                xFullPathname: function (pVfs, zName, nOut, pOut) {
                  return wasm.cstrncpy(pOut, zName, nOut) < nOut ? 0 : capi.SQLITE_CANTOPEN;
                },
                xGetLastError: function (pVfs, nOut, pOut) {
                  warn("OPFS xGetLastError() has nothing sensible to return.");
                  return 0;
                },
                xOpen: function f(pVfs, zName, pFile, flags, pOutFlags) {
                  mTimeStart("xOpen");
                  let opfsFlags = 0;
                  if (0 === zName) zName = randomFilename();else if (wasm.isPtr(zName)) {
                    if (capi.sqlite3_uri_boolean(zName, "opfs-unlock-asap", 0)) opfsFlags |= state.opfsFlags.OPFS_UNLOCK_ASAP;
                    if (capi.sqlite3_uri_boolean(zName, "delete-before-open", 0)) opfsFlags |= state.opfsFlags.OPFS_UNLINK_BEFORE_OPEN;
                    zName = wasm.cstrToJs(zName);
                  }
                  const fh = Object.create(null);
                  fh.fid = pFile;
                  fh.filename = zName;
                  fh.sab = new SharedArrayBuffer(state.fileBufferSize);
                  fh.flags = flags;
                  fh.readOnly = !(capi.SQLITE_OPEN_CREATE & flags) && !!(flags & capi.SQLITE_OPEN_READONLY);
                  const rc = opRun("xOpen", pFile, zName, flags, opfsFlags);
                  if (!rc) {
                    if (fh.readOnly) wasm.poke(pOutFlags, capi.SQLITE_OPEN_READONLY, "i32");
                    __openFiles[pFile] = fh;
                    fh.sabView = state.sabFileBufView;
                    fh.sq3File = new sqlite3_file(pFile);
                    fh.sq3File.$pMethods = opfsIoMethods.pointer;
                    fh.lockType = capi.SQLITE_LOCK_NONE;
                  }
                  mTimeEnd();
                  return rc;
                }
              };
              if (dVfs) {
                opfsVfs.$xRandomness = dVfs.$xRandomness;
                opfsVfs.$xSleep = dVfs.$xSleep;
              }
              if (!opfsVfs.$xRandomness) vfsSyncWrappers.xRandomness = function (pVfs, nOut, pOut) {
                const heap = wasm.heap8u();
                let i = 0;
                const npOut = Number(pOut);
                for (; i < nOut; ++i) heap[npOut + i] = Math.random() * 255e3 & 255;
                return i;
              };
              if (!opfsVfs.$xSleep) vfsSyncWrappers.xSleep = function (pVfs, ms) {
                Atomics.wait(state.sabOPView, state.opIds.xSleep, 0, ms);
                return 0;
              };
              opfsUtil.getResolvedPath = function (filename, splitIt) {
                const p = new URL(filename, "file://irrelevant").pathname;
                return splitIt ? p.split("/").filter(v => !!v) : p;
              };
              opfsUtil.getDirForFilename = async function f(absFilename, createDirs = false) {
                const path = opfsUtil.getResolvedPath(absFilename, true);
                const filename = path.pop();
                let dh = opfsUtil.rootDirectory;
                for (const dirName of path) if (dirName) dh = await dh.getDirectoryHandle(dirName, {
                  create: !!createDirs
                });
                return [dh, filename];
              };
              opfsUtil.mkdir = async function (absDirName) {
                try {
                  await opfsUtil.getDirForFilename(absDirName + "/filepart", true);
                  return true;
                } catch (e) {
                  return false;
                }
              };
              opfsUtil.entryExists = async function (fsEntryName) {
                try {
                  const [dh, fn] = await opfsUtil.getDirForFilename(fsEntryName);
                  await dh.getFileHandle(fn);
                  return true;
                } catch (e) {
                  return false;
                }
              };
              opfsUtil.randomFilename = randomFilename;
              opfsUtil.treeList = async function () {
                const doDir = async function callee(dirHandle, tgt) {
                  tgt.name = dirHandle.name;
                  tgt.dirs = [];
                  tgt.files = [];
                  for await (const handle of dirHandle.values()) if ("directory" === handle.kind) {
                    const subDir = Object.create(null);
                    tgt.dirs.push(subDir);
                    await callee(handle, subDir);
                  } else tgt.files.push(handle.name);
                };
                const root = Object.create(null);
                await doDir(opfsUtil.rootDirectory, root);
                return root;
              };
              opfsUtil.rmfr = async function () {
                const dir = opfsUtil.rootDirectory,
                  opt = {
                    recurse: true
                  };
                for await (const handle of dir.values()) dir.removeEntry(handle.name, opt);
              };
              opfsUtil.unlink = async function (fsEntryName, recursive = false, throwOnError = false) {
                try {
                  const [hDir, filenamePart] = await opfsUtil.getDirForFilename(fsEntryName, false);
                  await hDir.removeEntry(filenamePart, {
                    recursive
                  });
                  return true;
                } catch (e) {
                  if (throwOnError) throw new Error("unlink(", arguments[0], ") failed: " + e.message, {
                    cause: e
                  });
                  return false;
                }
              };
              opfsUtil.traverse = async function (opt) {
                const defaultOpt = {
                  recursive: true,
                  directory: opfsUtil.rootDirectory
                };
                if ("function" === typeof opt) opt = {
                  callback: opt
                };
                opt = Object.assign(defaultOpt, opt || {});
                (async function callee(dirHandle, depth) {
                  for await (const handle of dirHandle.values()) if (false === opt.callback(handle, dirHandle, depth)) return false;else if (opt.recursive && "directory" === handle.kind) {
                    if (false === (await callee(handle, depth + 1))) break;
                  }
                })(opt.directory, 0);
              };
              const importDbChunked = async function (filename, callback) {
                const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true);
                let sah = await (await hDir.getFileHandle(fnamePart, {
                    create: true
                  })).createSyncAccessHandle(),
                  nWrote = 0,
                  chunk,
                  checkedHeader = false;
                try {
                  sah.truncate(0);
                  while (void 0 !== (chunk = await callback())) {
                    if (chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk);
                    if (!checkedHeader && 0 === nWrote && chunk.byteLength >= 15) {
                      util.affirmDbHeader(chunk);
                      checkedHeader = true;
                    }
                    sah.write(chunk, {
                      at: nWrote
                    });
                    nWrote += chunk.byteLength;
                  }
                  if (nWrote < 512 || 0 !== nWrote % 512) toss("Input size", nWrote, "is not correct for an SQLite database.");
                  if (!checkedHeader) {
                    const header = new Uint8Array(20);
                    sah.read(header, {
                      at: 0
                    });
                    util.affirmDbHeader(header);
                  }
                  sah.write(new Uint8Array([1, 1]), {
                    at: 18
                  });
                  return nWrote;
                } catch (e) {
                  await sah.close();
                  sah = void 0;
                  await hDir.removeEntry(fnamePart).catch(() => {});
                  throw e;
                } finally {
                  if (sah) await sah.close();
                }
              };
              opfsUtil.importDb = async function (filename, bytes) {
                if (bytes instanceof Function) return importDbChunked(filename, bytes);
                if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes);
                util.affirmIsDb(bytes);
                const n = bytes.byteLength;
                const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true);
                let sah,
                  nWrote = 0;
                try {
                  sah = await (await hDir.getFileHandle(fnamePart, {
                    create: true
                  })).createSyncAccessHandle();
                  sah.truncate(0);
                  nWrote = sah.write(bytes, {
                    at: 0
                  });
                  if (nWrote != n) toss("Expected to write " + n + " bytes but wrote " + nWrote + ".");
                  sah.write(new Uint8Array([1, 1]), {
                    at: 18
                  });
                  return nWrote;
                } catch (e) {
                  if (sah) {
                    await sah.close();
                    sah = void 0;
                  }
                  await hDir.removeEntry(fnamePart).catch(() => {});
                  throw e;
                } finally {
                  if (sah) await sah.close();
                }
              };
              if (sqlite3.oo1) {
                const OpfsDb = function (...args) {
                  const opt = sqlite3.oo1.DB.dbCtorHelper.normalizeArgs(...args);
                  opt.vfs = opfsVfs.$zName;
                  sqlite3.oo1.DB.dbCtorHelper.call(this, opt);
                };
                OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
                sqlite3.oo1.OpfsDb = OpfsDb;
                OpfsDb.importDb = opfsUtil.importDb;
                sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenCallback(opfsVfs.pointer, function (oo1Db, sqlite3) {
                  sqlite3.capi.sqlite3_busy_timeout(oo1Db, 1e4);
                });
              }
              const sanityCheck = function () {
                const scope = wasm.scopedAllocPush();
                const sq3File = new sqlite3_file();
                try {
                  const fid = sq3File.pointer;
                  const openFlags = capi.SQLITE_OPEN_CREATE | capi.SQLITE_OPEN_READWRITE | capi.SQLITE_OPEN_MAIN_DB;
                  const pOut = wasm.scopedAlloc(8);
                  const dbFile = "/sanity/check/file" + randomFilename(8);
                  const zDbFile = wasm.scopedAllocCString(dbFile);
                  let rc;
                  state.s11n.serialize("This is ä string.");
                  rc = state.s11n.deserialize();
                  log("deserialize() says:", rc);
                  if ("This is ä string." !== rc[0]) toss("String d13n error.");
                  vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut);
                  rc = wasm.peek(pOut, "i32");
                  log("xAccess(", dbFile, ") exists ?=", rc);
                  rc = vfsSyncWrappers.xOpen(opfsVfs.pointer, zDbFile, fid, openFlags, pOut);
                  log("open rc =", rc, "state.sabOPView[xOpen] =", state.sabOPView[state.opIds.xOpen]);
                  if (0 !== rc) {
                    error("open failed with code", rc);
                    return;
                  }
                  vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut);
                  rc = wasm.peek(pOut, "i32");
                  if (!rc) toss("xAccess() failed to detect file.");
                  rc = ioSyncWrappers.xSync(sq3File.pointer, 0);
                  if (rc) toss("sync failed w/ rc", rc);
                  rc = ioSyncWrappers.xTruncate(sq3File.pointer, 1024);
                  if (rc) toss("truncate failed w/ rc", rc);
                  wasm.poke(pOut, 0, "i64");
                  rc = ioSyncWrappers.xFileSize(sq3File.pointer, pOut);
                  if (rc) toss("xFileSize failed w/ rc", rc);
                  log("xFileSize says:", wasm.peek(pOut, "i64"));
                  rc = ioSyncWrappers.xWrite(sq3File.pointer, zDbFile, 10, 1);
                  if (rc) toss("xWrite() failed!");
                  const readBuf = wasm.scopedAlloc(16);
                  rc = ioSyncWrappers.xRead(sq3File.pointer, readBuf, 6, 2);
                  wasm.poke(readBuf + 6, 0);
                  let jRead = wasm.cstrToJs(readBuf);
                  log("xRead() got:", jRead);
                  if ("sanity" !== jRead) toss("Unexpected xRead() value.");
                  if (vfsSyncWrappers.xSleep) {
                    log("xSleep()ing before close()ing...");
                    vfsSyncWrappers.xSleep(opfsVfs.pointer, 2e3);
                    log("waking up from xSleep()");
                  }
                  rc = ioSyncWrappers.xClose(fid);
                  log("xClose rc =", rc, "sabOPView =", state.sabOPView);
                  log("Deleting file:", dbFile);
                  vfsSyncWrappers.xDelete(opfsVfs.pointer, zDbFile, 4660);
                  vfsSyncWrappers.xAccess(opfsVfs.pointer, zDbFile, 0, pOut);
                  rc = wasm.peek(pOut, "i32");
                  if (rc) toss("Expecting 0 from xAccess(", dbFile, ") after xDelete().");
                  warn("End of OPFS sanity checks.");
                } finally {
                  sq3File.dispose();
                  wasm.scopedAllocPop(scope);
                }
              };
              W.onmessage = function ({
                data
              }) {
                switch (data.type) {
                  case "opfs-unavailable":
                    promiseReject(new Error(data.payload.join(" ")));
                    break;
                  case "opfs-async-loaded":
                    W.postMessage({
                      type: "opfs-async-init",
                      args: state
                    });
                    break;
                  case "opfs-async-inited":
                    if (true === promiseWasRejected) break;
                    try {
                      sqlite3.vfs.installVfs({
                        io: {
                          struct: opfsIoMethods,
                          methods: ioSyncWrappers
                        },
                        vfs: {
                          struct: opfsVfs,
                          methods: vfsSyncWrappers
                        }
                      });
                      state.sabOPView = new Int32Array(state.sabOP);
                      state.sabFileBufView = new Uint8Array(state.sabIO, 0, state.fileBufferSize);
                      state.sabS11nView = new Uint8Array(state.sabIO, state.sabS11nOffset, state.sabS11nSize);
                      initS11n();
                      if (options.sanityChecks) {
                        warn("Running sanity checks because of opfs-sanity-check URL arg...");
                        sanityCheck();
                      }
                      if (thisThreadHasOPFS()) navigator.storage.getDirectory().then(d => {
                        W.onerror = W._originalOnError;
                        delete W._originalOnError;
                        sqlite3.opfs = opfsUtil;
                        opfsUtil.rootDirectory = d;
                        log("End of OPFS sqlite3_vfs setup.", opfsVfs);
                        promiseResolve();
                      }).catch(promiseReject);else promiseResolve();
                    } catch (e) {
                      error(e);
                      promiseReject(e);
                    }
                    break;
                  default:
                    {
                      const errMsg = "Unexpected message from the OPFS async worker: " + JSON.stringify(data);
                      error(errMsg);
                      promiseReject(new Error(errMsg));
                      break;
                    }
                }
              };
            });
          };
          installOpfsVfs.defaultProxyUri = "sqlite3-opfs-async-proxy.js";
          globalThis.sqlite3ApiBootstrap.initializersAsync.push(async sqlite3 => {
            try {
              let proxyJs = installOpfsVfs.defaultProxyUri;
              if (sqlite3?.scriptInfo?.sqlite3Dir) installOpfsVfs.defaultProxyUri = sqlite3.scriptInfo.sqlite3Dir + proxyJs;
              return installOpfsVfs().catch(e => {
                sqlite3.config.warn("Ignoring inability to install OPFS sqlite3_vfs:", e.message);
              });
            } catch (e) {
              sqlite3.config.error("installOpfsVfs() exception:", e);
              return Promise.reject(e);
            }
          });
        });
        globalThis.sqlite3ApiBootstrap.initializers.push(function (sqlite3) {

          const toss = sqlite3.util.toss;
          const toss3 = sqlite3.util.toss3;
          const initPromises = Object.create(null);
          const capi = sqlite3.capi;
          const util = sqlite3.util;
          const wasm = sqlite3.wasm;
          const SECTOR_SIZE = 4096;
          const HEADER_MAX_PATH_SIZE = 512;
          const HEADER_FLAGS_SIZE = 4;
          const HEADER_DIGEST_SIZE = 8;
          const HEADER_CORPUS_SIZE = HEADER_MAX_PATH_SIZE + HEADER_FLAGS_SIZE;
          const HEADER_OFFSET_FLAGS = HEADER_MAX_PATH_SIZE;
          const HEADER_OFFSET_DIGEST = HEADER_CORPUS_SIZE;
          const HEADER_OFFSET_DATA = SECTOR_SIZE;
          const PERSISTENT_FILE_TYPES = capi.SQLITE_OPEN_MAIN_DB | capi.SQLITE_OPEN_MAIN_JOURNAL | capi.SQLITE_OPEN_SUPER_JOURNAL | capi.SQLITE_OPEN_WAL;
          const FLAG_COMPUTE_DIGEST_V2 = capi.SQLITE_OPEN_MEMORY;
          const OPAQUE_DIR_NAME = ".opaque";
          const getRandomName = () => Math.random().toString(36).slice(2);
          const textDecoder = new TextDecoder();
          const textEncoder = new TextEncoder();
          const optionDefaults = Object.assign(Object.create(null), {
            name: "opfs-sahpool",
            directory: void 0,
            initialCapacity: 6,
            clearOnInit: false,
            verbosity: 2,
            forceReinitIfPreviouslyFailed: false
          });
          const loggers = [sqlite3.config.error, sqlite3.config.warn, sqlite3.config.log];
          sqlite3.config.log;
          const warn = sqlite3.config.warn;
          sqlite3.config.error;
          const __mapVfsToPool = /* @__PURE__ */new Map();
          const getPoolForVfs = pVfs => __mapVfsToPool.get(pVfs);
          const setPoolForVfs = (pVfs, pool) => {
            if (pool) __mapVfsToPool.set(pVfs, pool);else __mapVfsToPool.delete(pVfs);
          };
          const __mapSqlite3File = /* @__PURE__ */new Map();
          const getPoolForPFile = pFile => __mapSqlite3File.get(pFile);
          const setPoolForPFile = (pFile, pool) => {
            if (pool) __mapSqlite3File.set(pFile, pool);else __mapSqlite3File.delete(pFile);
          };
          const ioMethods = {
            xCheckReservedLock: function (pFile, pOut) {
              const pool = getPoolForPFile(pFile);
              pool.log("xCheckReservedLock");
              pool.storeErr();
              wasm.poke32(pOut, 1);
              return 0;
            },
            xClose: function (pFile) {
              const pool = getPoolForPFile(pFile);
              pool.storeErr();
              const file = pool.getOFileForS3File(pFile);
              if (file) try {
                pool.log(`xClose ${file.path}`);
                pool.mapS3FileToOFile(pFile, false);
                file.sah.flush();
                if (file.flags & capi.SQLITE_OPEN_DELETEONCLOSE) pool.deletePath(file.path);
              } catch (e) {
                return pool.storeErr(e, capi.SQLITE_IOERR);
              }
              return 0;
            },
            xDeviceCharacteristics: function (pFile) {
              return capi.SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN;
            },
            xFileControl: function (pFile, opId, pArg) {
              return capi.SQLITE_NOTFOUND;
            },
            xFileSize: function (pFile, pSz64) {
              const pool = getPoolForPFile(pFile);
              pool.log(`xFileSize`);
              const size = pool.getOFileForS3File(pFile).sah.getSize() - HEADER_OFFSET_DATA;
              wasm.poke64(pSz64, BigInt(size));
              return 0;
            },
            xLock: function (pFile, lockType) {
              const pool = getPoolForPFile(pFile);
              pool.log(`xLock ${lockType}`);
              pool.storeErr();
              const file = pool.getOFileForS3File(pFile);
              file.lockType = lockType;
              return 0;
            },
            xRead: function (pFile, pDest, n, offset64) {
              const pool = getPoolForPFile(pFile);
              pool.storeErr();
              const file = pool.getOFileForS3File(pFile);
              pool.log(`xRead ${file.path} ${n} @ ${offset64}`);
              try {
                const nRead = file.sah.read(wasm.heap8u().subarray(Number(pDest), Number(pDest) + n), {
                  at: HEADER_OFFSET_DATA + Number(offset64)
                });
                if (nRead < n) {
                  wasm.heap8u().fill(0, Number(pDest) + nRead, Number(pDest) + n);
                  return capi.SQLITE_IOERR_SHORT_READ;
                }
                return 0;
              } catch (e) {
                return pool.storeErr(e, capi.SQLITE_IOERR);
              }
            },
            xSectorSize: function (pFile) {
              return SECTOR_SIZE;
            },
            xSync: function (pFile, flags) {
              const pool = getPoolForPFile(pFile);
              pool.log(`xSync ${flags}`);
              pool.storeErr();
              const file = pool.getOFileForS3File(pFile);
              try {
                file.sah.flush();
                return 0;
              } catch (e) {
                return pool.storeErr(e, capi.SQLITE_IOERR);
              }
            },
            xTruncate: function (pFile, sz64) {
              const pool = getPoolForPFile(pFile);
              pool.log(`xTruncate ${sz64}`);
              pool.storeErr();
              const file = pool.getOFileForS3File(pFile);
              try {
                file.sah.truncate(HEADER_OFFSET_DATA + Number(sz64));
                return 0;
              } catch (e) {
                return pool.storeErr(e, capi.SQLITE_IOERR);
              }
            },
            xUnlock: function (pFile, lockType) {
              const pool = getPoolForPFile(pFile);
              pool.log("xUnlock");
              const file = pool.getOFileForS3File(pFile);
              file.lockType = lockType;
              return 0;
            },
            xWrite: function (pFile, pSrc, n, offset64) {
              const pool = getPoolForPFile(pFile);
              pool.storeErr();
              const file = pool.getOFileForS3File(pFile);
              pool.log(`xWrite ${file.path} ${n} ${offset64}`);
              try {
                return n === file.sah.write(wasm.heap8u().subarray(Number(pSrc), Number(pSrc) + n), {
                  at: HEADER_OFFSET_DATA + Number(offset64)
                }) ? 0 : toss("Unknown write() failure.");
              } catch (e) {
                return pool.storeErr(e, capi.SQLITE_IOERR);
              }
            }
          };
          const opfsIoMethods = new capi.sqlite3_io_methods();
          opfsIoMethods.$iVersion = 1;
          sqlite3.vfs.installVfs({
            io: {
              struct: opfsIoMethods,
              methods: ioMethods
            }
          });
          const vfsMethods = {
            xAccess: function (pVfs, zName, flags, pOut) {
              const pool = getPoolForVfs(pVfs);
              pool.storeErr();
              try {
                const name = pool.getPath(zName);
                wasm.poke32(pOut, pool.hasFilename(name) ? 1 : 0);
              } catch (e) {
                wasm.poke32(pOut, 0);
              }
              return 0;
            },
            xCurrentTime: function (pVfs, pOut) {
              wasm.poke(pOut, 2440587.5 + (/* @__PURE__ */new Date()).getTime() / 864e5, "double");
              return 0;
            },
            xCurrentTimeInt64: function (pVfs, pOut) {
              wasm.poke(pOut, 2440587.5 * 864e5 + (/* @__PURE__ */new Date()).getTime(), "i64");
              return 0;
            },
            xDelete: function (pVfs, zName, doSyncDir) {
              const pool = getPoolForVfs(pVfs);
              pool.log(`xDelete ${wasm.cstrToJs(zName)}`);
              pool.storeErr();
              try {
                pool.deletePath(pool.getPath(zName));
                return 0;
              } catch (e) {
                pool.storeErr(e);
                return capi.SQLITE_IOERR_DELETE;
              }
            },
            xFullPathname: function (pVfs, zName, nOut, pOut) {
              return wasm.cstrncpy(pOut, zName, nOut) < nOut ? 0 : capi.SQLITE_CANTOPEN;
            },
            xGetLastError: function (pVfs, nOut, pOut) {
              const pool = getPoolForVfs(pVfs);
              const e = pool.popErr();
              pool.log(`xGetLastError ${nOut} e =`, e);
              if (e) {
                const scope = wasm.scopedAllocPush();
                try {
                  const [cMsg, n] = wasm.scopedAllocCString(e.message, true);
                  wasm.cstrncpy(pOut, cMsg, nOut);
                  if (n > nOut) wasm.poke8(wasm.ptr.add(pOut, nOut, -1), 0);
                } catch (e) {
                  return capi.SQLITE_NOMEM;
                } finally {
                  wasm.scopedAllocPop(scope);
                }
              }
              return e ? e.sqlite3Rc || capi.SQLITE_IOERR : 0;
            },
            xOpen: function f(pVfs, zName, pFile, flags, pOutFlags) {
              const pool = getPoolForVfs(pVfs);
              try {
                flags &= ~FLAG_COMPUTE_DIGEST_V2;
                pool.log(`xOpen ${wasm.cstrToJs(zName)} ${flags}`);
                const path = zName && wasm.peek8(zName) ? pool.getPath(zName) : getRandomName();
                let sah = pool.getSAHForPath(path);
                if (!sah && flags & capi.SQLITE_OPEN_CREATE) if (pool.getFileCount() < pool.getCapacity()) {
                  sah = pool.nextAvailableSAH();
                  pool.setAssociatedPath(sah, path, flags);
                } else toss("SAH pool is full. Cannot create file", path);
                if (!sah) toss("file not found:", path);
                const file = {
                  path,
                  flags,
                  sah
                };
                pool.mapS3FileToOFile(pFile, file);
                file.lockType = capi.SQLITE_LOCK_NONE;
                const sq3File = new capi.sqlite3_file(pFile);
                sq3File.$pMethods = opfsIoMethods.pointer;
                sq3File.dispose();
                wasm.poke32(pOutFlags, flags);
                return 0;
              } catch (e) {
                pool.storeErr(e);
                return capi.SQLITE_CANTOPEN;
              }
            }
          };
          const createOpfsVfs = function (vfsName) {
            if (sqlite3.capi.sqlite3_vfs_find(vfsName)) toss3("VFS name is already registered:", vfsName);
            const opfsVfs = new capi.sqlite3_vfs();
            const pDVfs = capi.sqlite3_vfs_find(null);
            const dVfs = pDVfs ? new capi.sqlite3_vfs(pDVfs) : null;
            opfsVfs.$iVersion = 2;
            opfsVfs.$szOsFile = capi.sqlite3_file.structInfo.sizeof;
            opfsVfs.$mxPathname = HEADER_MAX_PATH_SIZE;
            opfsVfs.addOnDispose(opfsVfs.$zName = wasm.allocCString(vfsName), () => setPoolForVfs(opfsVfs.pointer, 0));
            if (dVfs) {
              opfsVfs.$xRandomness = dVfs.$xRandomness;
              opfsVfs.$xSleep = dVfs.$xSleep;
              dVfs.dispose();
            }
            if (!opfsVfs.$xRandomness && !vfsMethods.xRandomness) vfsMethods.xRandomness = function (pVfs, nOut, pOut) {
              const heap = wasm.heap8u();
              let i = 0;
              const npOut = Number(pOut);
              for (; i < nOut; ++i) heap[npOut + i] = Math.random() * 255e3 & 255;
              return i;
            };
            if (!opfsVfs.$xSleep && !vfsMethods.xSleep) vfsMethods.xSleep = (pVfs, ms) => 0;
            sqlite3.vfs.installVfs({
              vfs: {
                struct: opfsVfs,
                methods: vfsMethods
              }
            });
            return opfsVfs;
          };
          class OpfsSAHPool {
            vfsDir;
            #dhVfsRoot;
            #dhOpaque;
            #dhVfsParent;
            #mapSAHToName = /* @__PURE__ */new Map();
            #mapFilenameToSAH = /* @__PURE__ */new Map();
            #availableSAH = /* @__PURE__ */new Set();
            #mapS3FileToOFile_ = /* @__PURE__ */new Map();
            #apBody = new Uint8Array(HEADER_CORPUS_SIZE);
            #dvBody;
            #cVfs;
            #verbosity;
            constructor(options = Object.create(null)) {
              this.#verbosity = options.verbosity ?? optionDefaults.verbosity;
              this.vfsName = options.name || optionDefaults.name;
              this.#cVfs = createOpfsVfs(this.vfsName);
              setPoolForVfs(this.#cVfs.pointer, this);
              this.vfsDir = options.directory || "." + this.vfsName;
              this.#dvBody = new DataView(this.#apBody.buffer, this.#apBody.byteOffset);
              this.isReady = this.reset(!!(options.clearOnInit ?? optionDefaults.clearOnInit)).then(() => {
                if (this.$error) throw this.$error;
                return this.getCapacity() ? Promise.resolve(void 0) : this.addCapacity(options.initialCapacity || optionDefaults.initialCapacity);
              });
            }
            #logImpl(level, ...args) {
              if (this.#verbosity > level) loggers[level](this.vfsName + ":", ...args);
            }
            log(...args) {
              this.#logImpl(2, ...args);
            }
            warn(...args) {
              this.#logImpl(1, ...args);
            }
            error(...args) {
              this.#logImpl(0, ...args);
            }
            getVfs() {
              return this.#cVfs;
            }
            getCapacity() {
              return this.#mapSAHToName.size;
            }
            getFileCount() {
              return this.#mapFilenameToSAH.size;
            }
            getFileNames() {
              const rc = [];
              for (const n of this.#mapFilenameToSAH.keys()) rc.push(n);
              return rc;
            }
            async addCapacity(n) {
              for (let i = 0; i < n; ++i) {
                const name = getRandomName();
                const ah = await (await this.#dhOpaque.getFileHandle(name, {
                  create: true
                })).createSyncAccessHandle();
                this.#mapSAHToName.set(ah, name);
                this.setAssociatedPath(ah, "", 0);
              }
              return this.getCapacity();
            }
            async reduceCapacity(n) {
              let nRm = 0;
              for (const ah of Array.from(this.#availableSAH)) {
                if (nRm === n || this.getFileCount() === this.getCapacity()) break;
                const name = this.#mapSAHToName.get(ah);
                ah.close();
                await this.#dhOpaque.removeEntry(name);
                this.#mapSAHToName.delete(ah);
                this.#availableSAH.delete(ah);
                ++nRm;
              }
              return nRm;
            }
            releaseAccessHandles() {
              for (const ah of this.#mapSAHToName.keys()) ah.close();
              this.#mapSAHToName.clear();
              this.#mapFilenameToSAH.clear();
              this.#availableSAH.clear();
            }
            async acquireAccessHandles(clearFiles = false) {
              const files = [];
              for await (const [name, h] of this.#dhOpaque) if ("file" === h.kind) files.push([name, h]);
              return Promise.all(files.map(async ([name, h]) => {
                try {
                  const ah = await h.createSyncAccessHandle();
                  this.#mapSAHToName.set(ah, name);
                  if (clearFiles) {
                    ah.truncate(HEADER_OFFSET_DATA);
                    this.setAssociatedPath(ah, "", 0);
                  } else {
                    const path = this.getAssociatedPath(ah);
                    if (path) this.#mapFilenameToSAH.set(path, ah);else this.#availableSAH.add(ah);
                  }
                } catch (e) {
                  this.storeErr(e);
                  this.releaseAccessHandles();
                  throw e;
                }
              }));
            }
            getAssociatedPath(sah) {
              sah.read(this.#apBody, {
                at: 0
              });
              const flags = this.#dvBody.getUint32(HEADER_OFFSET_FLAGS);
              if (this.#apBody[0] && (flags & capi.SQLITE_OPEN_DELETEONCLOSE || (flags & PERSISTENT_FILE_TYPES) === 0)) {
                warn(`Removing file with unexpected flags ${flags.toString(16)}`, this.#apBody);
                this.setAssociatedPath(sah, "", 0);
                return "";
              }
              const fileDigest = new Uint32Array(HEADER_DIGEST_SIZE / 4);
              sah.read(fileDigest, {
                at: HEADER_OFFSET_DIGEST
              });
              const compDigest = this.computeDigest(this.#apBody, flags);
              if (fileDigest.every((v, i) => v === compDigest[i])) {
                const pathBytes = this.#apBody.findIndex(v => 0 === v);
                if (0 === pathBytes) sah.truncate(HEADER_OFFSET_DATA);
                return pathBytes ? textDecoder.decode(this.#apBody.subarray(0, pathBytes)) : "";
              } else {
                warn("Disassociating file with bad digest.");
                this.setAssociatedPath(sah, "", 0);
                return "";
              }
            }
            setAssociatedPath(sah, path, flags) {
              const enc = textEncoder.encodeInto(path, this.#apBody);
              if (HEADER_MAX_PATH_SIZE <= enc.written + 1) toss("Path too long:", path);
              if (path && flags) flags |= FLAG_COMPUTE_DIGEST_V2;
              this.#apBody.fill(0, enc.written, HEADER_MAX_PATH_SIZE);
              this.#dvBody.setUint32(HEADER_OFFSET_FLAGS, flags);
              const digest = this.computeDigest(this.#apBody, flags);
              sah.write(this.#apBody, {
                at: 0
              });
              sah.write(digest, {
                at: HEADER_OFFSET_DIGEST
              });
              sah.flush();
              if (path) {
                this.#mapFilenameToSAH.set(path, sah);
                this.#availableSAH.delete(sah);
              } else {
                sah.truncate(HEADER_OFFSET_DATA);
                this.#availableSAH.add(sah);
              }
            }
            computeDigest(byteArray, fileFlags) {
              if (fileFlags & FLAG_COMPUTE_DIGEST_V2) {
                let h1 = 3735928559;
                let h2 = 1103547991;
                for (const v of byteArray) {
                  h1 = Math.imul(h1 ^ v, 2654435761);
                  h2 = Math.imul(h2 ^ v, 104729);
                }
                return new Uint32Array([h1 >>> 0, h2 >>> 0]);
              } else return new Uint32Array([0, 0]);
            }
            async reset(clearFiles) {
              await this.isReady;
              let h = await navigator.storage.getDirectory(),
                prev;
              for (const d of this.vfsDir.split("/")) if (d) {
                prev = h;
                h = await h.getDirectoryHandle(d, {
                  create: true
                });
              }
              this.#dhVfsRoot = h;
              this.#dhVfsParent = prev;
              this.#dhOpaque = await this.#dhVfsRoot.getDirectoryHandle(OPAQUE_DIR_NAME, {
                create: true
              });
              this.releaseAccessHandles();
              return this.acquireAccessHandles(clearFiles);
            }
            getPath(arg) {
              if (wasm.isPtr(arg)) arg = wasm.cstrToJs(arg);
              return (arg instanceof URL ? arg : new URL(arg, "file://localhost/")).pathname;
            }
            deletePath(path) {
              const sah = this.#mapFilenameToSAH.get(path);
              if (sah) {
                this.#mapFilenameToSAH.delete(path);
                this.setAssociatedPath(sah, "", 0);
              }
              return !!sah;
            }
            storeErr(e, code) {
              if (e) {
                e.sqlite3Rc = code || capi.SQLITE_IOERR;
                this.error(e);
              }
              this.$error = e;
              return code;
            }
            popErr() {
              const rc = this.$error;
              this.$error = void 0;
              return rc;
            }
            nextAvailableSAH() {
              const [rc] = this.#availableSAH.keys();
              return rc;
            }
            getOFileForS3File(pFile) {
              return this.#mapS3FileToOFile_.get(pFile);
            }
            mapS3FileToOFile(pFile, file) {
              if (file) {
                this.#mapS3FileToOFile_.set(pFile, file);
                setPoolForPFile(pFile, this);
              } else {
                this.#mapS3FileToOFile_.delete(pFile);
                setPoolForPFile(pFile, false);
              }
            }
            hasFilename(name) {
              return this.#mapFilenameToSAH.has(name);
            }
            getSAHForPath(path) {
              return this.#mapFilenameToSAH.get(path);
            }
            async removeVfs() {
              if (!this.#cVfs.pointer || !this.#dhOpaque) return false;
              capi.sqlite3_vfs_unregister(this.#cVfs.pointer);
              this.#cVfs.dispose();
              delete initPromises[this.vfsName];
              try {
                this.releaseAccessHandles();
                await this.#dhVfsRoot.removeEntry(OPAQUE_DIR_NAME, {
                  recursive: true
                });
                this.#dhOpaque = void 0;
                await this.#dhVfsParent.removeEntry(this.#dhVfsRoot.name, {
                  recursive: true
                });
                this.#dhVfsRoot = this.#dhVfsParent = void 0;
              } catch (e) {
                sqlite3.config.error(this.vfsName, "removeVfs() failed with no recovery strategy:", e);
              }
              return true;
            }
            pauseVfs() {
              if (this.#mapS3FileToOFile_.size > 0) sqlite3.SQLite3Error.toss(capi.SQLITE_MISUSE, "Cannot pause VFS", this.vfsName, "because it has opened files.");
              if (this.#mapSAHToName.size > 0) {
                capi.sqlite3_vfs_unregister(this.vfsName);
                this.releaseAccessHandles();
              }
              return this;
            }
            isPaused() {
              return 0 === this.#mapSAHToName.size;
            }
            async unpauseVfs() {
              if (0 === this.#mapSAHToName.size) return this.acquireAccessHandles(false).then(() => capi.sqlite3_vfs_register(this.#cVfs, 0), this);
              return this;
            }
            //! Documented elsewhere in this file.
            exportFile(name) {
              const sah = this.#mapFilenameToSAH.get(name) || toss("File not found:", name);
              const n = sah.getSize() - HEADER_OFFSET_DATA;
              const b = new Uint8Array(n > 0 ? n : 0);
              if (n > 0) {
                const nRead = sah.read(b, {
                  at: HEADER_OFFSET_DATA
                });
                if (nRead != n) toss("Expected to read " + n + " bytes but read " + nRead + ".");
              }
              return b;
            }
            //! Impl for importDb() when its 2nd arg is a function.
            async importDbChunked(name, callback) {
              const sah = this.#mapFilenameToSAH.get(name) || this.nextAvailableSAH() || toss("No available handles to import to.");
              sah.truncate(0);
              let nWrote = 0,
                chunk,
                checkedHeader = false;
              try {
                while (void 0 !== (chunk = await callback())) {
                  if (chunk instanceof ArrayBuffer) chunk = new Uint8Array(chunk);
                  if (!checkedHeader && 0 === nWrote && chunk.byteLength >= 15) {
                    util.affirmDbHeader(chunk);
                    checkedHeader = true;
                  }
                  sah.write(chunk, {
                    at: HEADER_OFFSET_DATA + nWrote
                  });
                  nWrote += chunk.byteLength;
                }
                if (nWrote < 512 || 0 !== nWrote % 512) toss("Input size", nWrote, "is not correct for an SQLite database.");
                if (!checkedHeader) {
                  const header = new Uint8Array(20);
                  sah.read(header, {
                    at: 0
                  });
                  util.affirmDbHeader(header);
                }
                sah.write(new Uint8Array([1, 1]), {
                  at: HEADER_OFFSET_DATA + 18
                });
              } catch (e) {
                this.setAssociatedPath(sah, "", 0);
                throw e;
              }
              this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB);
              return nWrote;
            }
            //! Documented elsewhere in this file.
            importDb(name, bytes) {
              if (bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes);else if (bytes instanceof Function) return this.importDbChunked(name, bytes);
              const sah = this.#mapFilenameToSAH.get(name) || this.nextAvailableSAH() || toss("No available handles to import to.");
              const n = bytes.byteLength;
              if (n < 512 || n % 512 != 0) toss("Byte array size is invalid for an SQLite db.");
              const header = "SQLite format 3";
              for (let i = 0; i < 15; ++i) if (header.charCodeAt(i) !== bytes[i]) toss("Input does not contain an SQLite database header.");
              const nWrote = sah.write(bytes, {
                at: HEADER_OFFSET_DATA
              });
              if (nWrote != n) {
                this.setAssociatedPath(sah, "", 0);
                toss("Expected to write " + n + " bytes but wrote " + nWrote + ".");
              } else {
                sah.write(new Uint8Array([1, 1]), {
                  at: HEADER_OFFSET_DATA + 18
                });
                this.setAssociatedPath(sah, name, capi.SQLITE_OPEN_MAIN_DB);
              }
              return nWrote;
            }
          }
          class OpfsSAHPoolUtil {
            #p;
            constructor(sahPool) {
              this.#p = sahPool;
              this.vfsName = sahPool.vfsName;
            }
            async addCapacity(n) {
              return this.#p.addCapacity(n);
            }
            async reduceCapacity(n) {
              return this.#p.reduceCapacity(n);
            }
            getCapacity() {
              return this.#p.getCapacity(this.#p);
            }
            getFileCount() {
              return this.#p.getFileCount();
            }
            getFileNames() {
              return this.#p.getFileNames();
            }
            async reserveMinimumCapacity(min) {
              const c = this.#p.getCapacity();
              return c < min ? this.#p.addCapacity(min - c) : c;
            }
            exportFile(name) {
              return this.#p.exportFile(name);
            }
            importDb(name, bytes) {
              return this.#p.importDb(name, bytes);
            }
            async wipeFiles() {
              return this.#p.reset(true);
            }
            unlink(filename) {
              return this.#p.deletePath(filename);
            }
            async removeVfs() {
              return this.#p.removeVfs();
            }
            pauseVfs() {
              this.#p.pauseVfs();
              return this;
            }
            async unpauseVfs() {
              return this.#p.unpauseVfs().then(() => this);
            }
            isPaused() {
              return this.#p.isPaused();
            }
          }
          const apiVersionCheck = async () => {
            const dh = await navigator.storage.getDirectory();
            const fn = ".opfs-sahpool-sync-check-" + getRandomName();
            const close = (await (await dh.getFileHandle(fn, {
              create: true
            })).createSyncAccessHandle()).close();
            await close;
            await dh.removeEntry(fn);
            if (close?.then) toss("The local OPFS API is too old for opfs-sahpool:", "it has an async FileSystemSyncAccessHandle.close() method.");
            return true;
          };
          sqlite3.installOpfsSAHPoolVfs = async function (options = Object.create(null)) {
            options = Object.assign(Object.create(null), optionDefaults, options || {});
            const vfsName = options.name;
            if (options.$testThrowPhase1) throw options.$testThrowPhase1;
            if (initPromises[vfsName]) try {
              return await initPromises[vfsName];
            } catch (e) {
              if (options.forceReinitIfPreviouslyFailed) delete initPromises[vfsName];else throw e;
            }
            if (!globalThis.FileSystemHandle || !globalThis.FileSystemDirectoryHandle || !globalThis.FileSystemFileHandle || !globalThis.FileSystemFileHandle.prototype.createSyncAccessHandle || !navigator?.storage?.getDirectory) return initPromises[vfsName] = Promise.reject(/* @__PURE__ */new Error("Missing required OPFS APIs."));
            return initPromises[vfsName] = apiVersionCheck().then(async function () {
              if (options.$testThrowPhase2) throw options.$testThrowPhase2;
              const thePool = new OpfsSAHPool(options);
              return thePool.isReady.then(async () => {
                const poolUtil = new OpfsSAHPoolUtil(thePool);
                if (sqlite3.oo1) {
                  const oo1 = sqlite3.oo1;
                  const theVfs = thePool.getVfs();
                  const OpfsSAHPoolDb = function (...args) {
                    const opt = oo1.DB.dbCtorHelper.normalizeArgs(...args);
                    opt.vfs = theVfs.$zName;
                    oo1.DB.dbCtorHelper.call(this, opt);
                  };
                  OpfsSAHPoolDb.prototype = Object.create(oo1.DB.prototype);
                  poolUtil.OpfsSAHPoolDb = OpfsSAHPoolDb;
                }
                thePool.log("VFS initialized.");
                return poolUtil;
              }).catch(async e => {
                await thePool.removeVfs().catch(() => {});
                throw e;
              });
            }).catch(err => {
              return initPromises[vfsName] = Promise.reject(err);
            });
          };
        });
        try {
          const bootstrapConfig = Object.assign(Object.create(null), {
            memory: "undefined" !== typeof wasmMemory ? wasmMemory : EmscriptenModule["wasmMemory"],
            exports: "undefined" !== typeof wasmExports ? wasmExports : Object.prototype.hasOwnProperty.call(EmscriptenModule, "wasmExports") ? EmscriptenModule["wasmExports"] : EmscriptenModule["asm"]
          }, globalThis.sqlite3ApiBootstrap.defaultConfig, globalThis.sqlite3ApiConfig || {});
          sqlite3InitScriptInfo.debugModule("Bootstrapping lib config", bootstrapConfig);
          const p = globalThis.sqlite3ApiBootstrap(bootstrapConfig);
          delete globalThis.sqlite3ApiBootstrap;
          return p;
        } catch (e) {
          console.error("sqlite3ApiBootstrap() error:", e);
          throw e;
        }
      };
      if (runtimeInitialized) moduleRtn = Module;else moduleRtn = new Promise((resolve, reject) => {
        readyPromiseResolve = resolve;
        readyPromiseReject = reject;
      });
      return moduleRtn;
    }
    sqlite3InitModule = function () {
      const originalInit = sqlite3InitModule;
      if (!originalInit) throw new Error("Expecting sqlite3InitModule to be defined by the Emscripten build.");
      const sIMS = globalThis.sqlite3InitModuleState = Object.assign(Object.create(null), {
        moduleScript: globalThis?.document?.currentScript,
        isWorker: "undefined" !== typeof WorkerGlobalScope,
        location: globalThis.location,
        urlParams: globalThis?.location?.href ? new URL(globalThis.location.href).searchParams : new URLSearchParams(),
        wasmFilename: "sqlite3.wasm"
      });
      sIMS.debugModule = sIMS.urlParams.has("sqlite3.debugModule") ? (...args) => console.warn("sqlite3.debugModule:", ...args) : () => {};
      if (sIMS.urlParams.has("sqlite3.dir")) sIMS.sqlite3Dir = sIMS.urlParams.get("sqlite3.dir") + "/";else if (sIMS.moduleScript) {
        const li = sIMS.moduleScript.src.split("/");
        li.pop();
        sIMS.sqlite3Dir = li.join("/") + "/";
      }
      const sIM = globalThis.sqlite3InitModule = function ff(...args) {
        sIMS.emscriptenLocateFile = args[0]?.locateFile;
        sIMS.emscriptenInstantiateWasm = args[0]?.instantiateWasm;
        return originalInit(...args).then(EmscriptenModule => {
          sIMS.debugModule("sqlite3InitModule() sIMS =", sIMS);
          sIMS.debugModule("sqlite3InitModule() EmscriptenModule =", EmscriptenModule);
          const s = EmscriptenModule.runSQLite3PostLoadInit(sIMS, EmscriptenModule, !!ff.__isUnderTest);
          sIMS.debugModule("sqlite3InitModule() sqlite3 =", s);
          return s;
        }).catch(e => {
          console.error("Exception loading sqlite3 module:", e);
          throw e;
        });
      };
      sIM.ready = originalInit.ready;
      if (sIMS.moduleScript) {
        let src = sIMS.moduleScript.src.split("/");
        src.pop();
        sIMS.scriptDir = src.join("/") + "/";
      }
      sIMS.debugModule("extern-post-js.c-pp.js sqlite3InitModuleState =", sIMS);
      return sIM;
    }();
    var sqlite3_bundler_friendly_default = sqlite3InitModule;
    globalThis.sqlite3Worker1Promiser = function callee(config = callee.defaultConfig) {
      if (1 === arguments.length && "function" === typeof arguments[0]) {
        const f = config;
        config = Object.assign(Object.create(null), callee.defaultConfig);
        config.onready = f;
      } else config = Object.assign(Object.create(null), callee.defaultConfig, config);
      const handlerMap = Object.create(null);
      const noop = function () {};
      const err = config.onerror || noop;
      const debug = config.debug || noop;
      const idTypeMap = config.generateMessageId ? void 0 : Object.create(null);
      const genMsgId = config.generateMessageId || function (msg) {
        return msg.type + "#" + (idTypeMap[msg.type] = (idTypeMap[msg.type] || 0) + 1);
      };
      const toss = (...args) => {
        throw new Error(args.join(" "));
      };
      if (!config.worker) config.worker = callee.defaultConfig.worker;
      if ("function" === typeof config.worker) config.worker = config.worker();
      let dbId;
      let promiserFunc;
      config.worker.onmessage = function (ev) {
        ev = ev.data;
        debug("worker1.onmessage", ev);
        let msgHandler = handlerMap[ev.messageId];
        if (!msgHandler) {
          if (ev && "sqlite3-api" === ev.type && "worker1-ready" === ev.result) {
            if (config.onready) config.onready(promiserFunc);
            return;
          }
          msgHandler = handlerMap[ev.type];
          if (msgHandler && msgHandler.onrow) {
            msgHandler.onrow(ev);
            return;
          }
          if (config.onunhandled) config.onunhandled(arguments[0]);else err("sqlite3Worker1Promiser() unhandled worker message:", ev);
          return;
        }
        delete handlerMap[ev.messageId];
        switch (ev.type) {
          case "error":
            msgHandler.reject(ev);
            return;
          case "open":
            if (!dbId) dbId = ev.dbId;
            break;
          case "close":
            if (ev.dbId === dbId) dbId = void 0;
            break;
        }
        try {
          msgHandler.resolve(ev);
        } catch (e) {
          msgHandler.reject(e);
        }
      };
      return promiserFunc = function () {
        let msg;
        if (1 === arguments.length) msg = arguments[0];else if (2 === arguments.length) {
          msg = Object.create(null);
          msg.type = arguments[0];
          msg.args = arguments[1];
          msg.dbId = msg.args.dbId;
        } else toss("Invalid arguments for sqlite3Worker1Promiser()-created factory.");
        if (!msg.dbId && msg.type !== "open") msg.dbId = dbId;
        msg.messageId = genMsgId(msg);
        msg.departureTime = performance.now();
        const proxy = Object.create(null);
        proxy.message = msg;
        let rowCallbackId;
        if ("exec" === msg.type && msg.args) {
          if ("function" === typeof msg.args.callback) {
            rowCallbackId = msg.messageId + ":row";
            proxy.onrow = msg.args.callback;
            msg.args.callback = rowCallbackId;
            handlerMap[rowCallbackId] = proxy;
          } else if ("string" === typeof msg.args.callback) toss("exec callback may not be a string when using the Promise interface.");
        }
        let p = new Promise(function (resolve, reject) {
          proxy.resolve = resolve;
          proxy.reject = reject;
          handlerMap[msg.messageId] = proxy;
          debug("Posting", msg.type, "message to Worker dbId=" + (dbId || "default") + ":", msg);
          config.worker.postMessage(msg);
        });
        if (rowCallbackId) p = p.finally(() => delete handlerMap[rowCallbackId]);
        return p;
      };
    };
    globalThis.sqlite3Worker1Promiser.defaultConfig = {
      worker: function () {
        return new Worker(new URL("sqlite3-worker1.mjs", (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('dls-analysis.umd.js', document.baseURI).href))), {
          type: "module"
        });
      },
      onerror: (...args) => console.error("sqlite3Worker1Promiser():", ...args)
    };
    globalThis.sqlite3Worker1Promiser.v2 = function callee(config = callee.defaultConfig) {
      let oldFunc;
      if ("function" == typeof config) {
        oldFunc = config;
        config = {};
      } else if ("function" === typeof config?.onready) {
        oldFunc = config.onready;
        delete config.onready;
      }
      const promiseProxy = Object.create(null);
      config = Object.assign(config || Object.create(null), {
        onready: async function (func) {
          try {
            if (oldFunc) await oldFunc(func);
            promiseProxy.resolve(func);
          } catch (e) {
            promiseProxy.reject(e);
          }
        }
      });
      const p = new Promise(function (resolve, reject) {
        promiseProxy.resolve = resolve;
        promiseProxy.reject = reject;
      });
      try {
        this.original(config);
      } catch (e) {
        promiseProxy.reject(e);
      }
      return p;
    }.bind({
      original: sqlite3Worker1Promiser
    });
    globalThis.sqlite3Worker1Promiser.v2.defaultConfig = globalThis.sqlite3Worker1Promiser.defaultConfig;
    sqlite3Worker1Promiser.v2;
    delete globalThis.sqlite3Worker1Promiser;
    var src_default = sqlite3_bundler_friendly_default;

    // Auto-generated — do not edit. Regenerate with: npm run generate-wasm
    const sqlite3WasmGzBase64=" ";

    /**
     * Decode a base64-encoded gzip-compressed buffer using the native
     * DecompressionStream API (available in Node.js 18+ and modern browsers).
     * @param base64 - Base64-encoded gzip data
     * @returns The decompressed ArrayBuffer
     */
    async function decompressBase64Gzip(base64) {
      const compressed = Uint8Array.from(atob(base64), character => character.codePointAt(0));
      const stream = new Blob([compressed]).stream().pipeThrough(new DecompressionStream('gzip'));
      return new Response(stream).arrayBuffer();
    }
    /** Lazily decompress the embedded wasm (once). */
    let wasmBinaryPromise;
    function getWasmBinary() {
      wasmBinaryPromise ??= decompressBase64Gzip(sqlite3WasmGzBase64);
      return wasmBinaryPromise;
    }
    /**
     * Initialize the SQLite WASM runtime and deserialize an ArrayBuffer
     * into an in-memory SQLite database.
     * @param data - Raw bytes of a .zmes file (SQLite3 database)
     * @returns The opened database handle and sqlite3 runtime
     */
    async function openDatabase(data) {
      const wasmBinary = await getWasmBinary();
      // @ts-expect-error wasmBinary is a valid Emscripten option not exposed in the type declarations
      const sqlite3 = await src_default({
        wasmBinary
      });
      const uint8 = new Uint8Array(data);
      const database = new sqlite3.oo1.DB();
      if (database.pointer === undefined) {
        throw new Error('Failed to create SQLite database handle');
      }
      const dataPointer = sqlite3.wasm.allocFromTypedArray(uint8);
      const resultCode = sqlite3.capi.sqlite3_deserialize(database.pointer, 'main', dataPointer, uint8.byteLength, uint8.byteLength, sqlite3.capi.SQLITE_DESERIALIZE_FREEONCLOSE | sqlite3.capi.SQLITE_DESERIALIZE_RESIZEABLE);
      database.checkRc(resultCode);
      return {
        database,
        sqlite3
      };
    }

    /**
     * 6-byte marker that precedes each IEEE 754 double in
     * .NET BinaryFormatter serialized System.Double[] arrays.
     */
    const ENTRY_MARKER = new Uint8Array([0x06, 0x01, 0x01, 0x01, 0x02, 0x01]);
    /** Total bytes per entry: 6 marker bytes + 8 bytes for the double. */
    const ENTRY_SIZE = 14;
    /**
     * Decode a .NET BinaryFormatter serialized `System.Double[]` blob
     * into a `Float64Array`.
     *
     * The binary format consists of a ~205-byte type metadata header
     * followed by repeating 14-byte entries (6-byte marker + 8-byte
     * little-endian IEEE 754 double).
     * @param blob - Raw blob bytes from the database
     * @returns Decoded array of double-precision values
     */
    function decodeBlob(blob) {
      const markerOffset = findMarker(blob);
      if (markerOffset === -1) {
        return new Float64Array(0);
      }
      const remainingBytes = blob.byteLength - markerOffset;
      const count = Math.floor(remainingBytes / ENTRY_SIZE);
      const result = new Float64Array(count);
      const dataView = new DataView(blob.buffer, blob.byteOffset, blob.byteLength);
      for (let i = 0; i < count; i++) {
        result[i] = dataView.getFloat64(markerOffset + i * ENTRY_SIZE + 6, true);
      }
      return result;
    }
    /**
     * Find the byte offset of the first occurrence of ENTRY_MARKER in the blob.
     * @param blob - Raw blob bytes
     * @returns Byte offset of the marker, or -1 if not found
     */
    function findMarker(blob) {
      const end = blob.byteLength - ENTRY_MARKER.length;
      for (let i = 0; i <= end; i++) {
        let match = true;
        for (let j = 0; j < ENTRY_MARKER.length; j++) {
          if (blob[i + j] !== ENTRY_MARKER[j]) {
            match = false;
            break;
          }
        }
        if (match) {
          return i;
        }
      }
      return -1;
    }

    /**
     * Data type values from RecordParameterTypes.ParameterDataType.
     * Determines which column in RecordParameterData holds the actual value.
     */
    const DATA_TYPE_NONE = 0;
    const DATA_TYPE_INT32_SINGLE = 1;
    const DATA_TYPE_INT32 = 2;
    const DATA_TYPE_DOUBLE = 4;
    const DATA_TYPE_SINGLE = 5;
    const DATA_TYPE_BOOLEAN = 6;
    const DATA_TYPE_INT64_SINGLE = 7;
    const DATA_TYPE_INT64 = 9;
    const DATA_TYPE_GUID = 16;
    const DATA_TYPE_TEXT = 17;
    const DATA_TYPE_DICTIONARY_KEYS = 32;
    const DATA_TYPE_DICTIONARY = 36;
    const DATA_TYPE_GUID_LIST = 42;
    const DATA_TYPE_DATE_TIME = 48;
    const DATA_TYPE_DURATION = 50;
    const DATA_TYPE_BLOB_ARRAY = 70;
    /**
     * Read all parameter data for a record and convert the tree into
     * the output ZmesParameter format.
     * @param database - Opened SQLite database handle
     * @param sqlite3 - SQLite3 runtime (needed for SQLITE_BLOB constant)
     * @param recordId - The record id to read data for
     * @param rootNode - The root of the parameter tree
     * @returns The root ZmesParameter with values attached
     */
    function readParameterData(database, sqlite3, recordId, rootNode) {
      // Load all data for this record, indexed by tree node id
      const dataByNodeId = loadDataMap(database, sqlite3, recordId);
      // Recursively convert tree nodes to output format
      return convertNode(rootNode, dataByNodeId);
    }
    /**
     * Load all RecordParameterData rows for a record into a Map
     * keyed by ParameterTreeNodeId.
     * @param database - Opened SQLite database handle
     * @param sqlite3 - SQLite3 runtime
     * @param recordId - The record id
     * @returns Map of tree node id to raw data row
     */
    function loadDataMap(database, sqlite3, recordId) {
      const rows = database.selectObjects(`
    SELECT
      ParameterTreeNodeId AS parameterTreeNodeId,
      ParameterTypeId     AS parameterTypeId,
      Data_Boolean        AS dataBoolean,
      Data_Double         AS dataDouble,
      Data_Int32          AS dataInt32,
      Data_Int64          AS dataInt64,
      Data_Single         AS dataSingle,
      Data_Text           AS dataText
    FROM RecordParameterData
    WHERE RecordId = ?
    ORDER BY Id
  `, [recordId]);
      // Also load blobs separately since they need special retrieval
      const blobRows = database.selectObjects(`
    SELECT
      ParameterTreeNodeId AS parameterTreeNodeId,
      Data_Blob           AS dataBlob
    FROM RecordParameterData
    WHERE RecordId = ? AND Data_Blob IS NOT NULL
  `, [recordId]);
      const blobMap = new Map();
      for (const blobRow of blobRows) {
        const nodeId = blobRow.parameterTreeNodeId;
        blobMap.set(nodeId, blobRow.dataBlob);
      }
      const dataMap = new Map();
      for (const row of rows) {
        const raw = row;
        dataMap.set(raw.parameterTreeNodeId, {
          ...raw,
          dataBlob: blobMap.get(raw.parameterTreeNodeId) ?? null
        });
      }
      return dataMap;
    }
    /**
     * Recursively convert a TreeNode into a ZmesParameter,
     * extracting the appropriate value from the data map.
     * @param node - The tree node to convert
     * @param dataMap - Map of tree node id to raw data
     * @returns The converted ZmesParameter
     */
    function convertNode(node, dataMap) {
      const parameter = {
        name: node.parameterType.friendlyName ?? '',
        urn: node.parameterType.urn ?? ''
      };
      // Extract value from the data row based on the parameter's data type
      const dataRow = dataMap.get(node.id);
      if (dataRow) {
        const value = extractValue(node.parameterType.dataType, dataRow);
        if (value !== undefined) {
          parameter.value = value;
        }
      }
      // Recursively convert children
      if (node.children.length > 0) {
        parameter.children = [];
        for (const child of node.children) {
          parameter.children.push(convertNode(child, dataMap));
        }
      }
      return parameter;
    }
    /**
     * Extract the typed value from a raw data row based on the parameter data type.
     *
     * Note: SQLite stores both Data_Single and Data_Double as its native REAL type,
     * so the WASM layer may return the value in either column. We use a fallback
     * approach for numeric types to handle this.
     * @param dataType - The ParameterDataType enum value
     * @param row - The raw data row
     * @returns The extracted value, or undefined if no value is present
     */
    function extractValue(dataType, row) {
      switch (dataType) {
        case DATA_TYPE_NONE:
        case DATA_TYPE_DICTIONARY:
          return undefined;
        case DATA_TYPE_INT32_SINGLE:
        case DATA_TYPE_INT32:
          return row.dataInt32 ?? undefined;
        case DATA_TYPE_DOUBLE:
        case DATA_TYPE_SINGLE:
        case DATA_TYPE_DURATION:
          return row.dataDouble ?? row.dataSingle ?? undefined;
        case DATA_TYPE_BOOLEAN:
          return row.dataBoolean !== null ? row.dataBoolean !== 0 : undefined;
        case DATA_TYPE_INT64_SINGLE:
          return row.dataInt64 ?? row.dataInt32 ?? undefined;
        case DATA_TYPE_INT64:
          return row.dataInt64 ?? undefined;
        case DATA_TYPE_GUID:
        case DATA_TYPE_TEXT:
        case DATA_TYPE_DICTIONARY_KEYS:
        case DATA_TYPE_GUID_LIST:
        case DATA_TYPE_DATE_TIME:
          return row.dataText ?? undefined;
        case DATA_TYPE_BLOB_ARRAY:
          if (row.dataBlob) {
            return decodeBlob(row.dataBlob);
          }
          return undefined;
        default:
          return undefined;
      }
    }

    /**
     * Load all parameter types from RecordParameterTypes into a Map.
     * @param database - Opened SQLite database handle
     * @returns Map of type id to ParameterType
     */
    function loadParameterTypes(database) {
      const rows = database.selectObjects(`
    SELECT
      Id                AS id,
      Guid              AS guid,
      UniformResourceName AS urn,
      FriendlyName      AS friendlyName,
      ParameterDataType AS dataType,
      Description       AS description,
      DataUnitsUrn      AS dataUnitsUrn
    FROM RecordParameterTypes
  `);
      const types = new Map();
      for (const row of rows) {
        const parameterType = row;
        types.set(parameterType.id, parameterType);
      }
      return types;
    }
    /**
     * Build the hierarchical parameter tree for a given root parameter type.
     *
     * Queries all tree nodes that share the given root type, resolves their
     * parameter types, and assembles them into a tree structure.
     * @param database - Opened SQLite database handle
     * @param rootParameterTypeId - The root parameter type id for the record
     * @returns The root TreeNode with all children populated
     */
    function buildParameterTree(database, rootParameterTypeId) {
      const parameterTypes = loadParameterTypes(database);
      const rows = database.selectObjects(`
    SELECT
      Id              AS id,
      ParameterTypeId AS parameterTypeId,
      ParentNodeId    AS parentNodeId,
      SiblingIndex    AS siblingIndex
    FROM RecordParameterTreeNodes
    WHERE RootParameterTypeId = ?
    ORDER BY SiblingIndex
  `, [rootParameterTypeId]);
      // Index all nodes by id
      const nodeMap = new Map();
      for (const row of rows) {
        const rawNode = row;
        const parameterType = parameterTypes.get(rawNode.parameterTypeId);
        if (!parameterType) {
          throw new Error(`Unknown parameter type id ${rawNode.parameterTypeId} for tree node ${rawNode.id}`);
        }
        nodeMap.set(rawNode.id, {
          ...rawNode,
          parameterType,
          children: []
        });
      }
      // Assemble tree by linking children to parents
      let root;
      for (const node of nodeMap.values()) {
        if (node.parentNodeId === null) {
          root = node;
        } else {
          const parent = nodeMap.get(node.parentNodeId);
          if (parent) {
            parent.children.push(node);
          }
        }
      }
      if (!root) {
        throw new Error(`No root tree node found for RootParameterTypeId ${rootParameterTypeId}`);
      }
      // Sort children by sibling index at each level
      sortChildren(root);
      return root;
    }
    /**
     * Recursively sort children of each tree node by sibling index.
     * @param node - The tree node whose children to sort
     */
    function sortChildren(node) {
      node.children = node.children.toSorted((a, b) => a.siblingIndex - b.siblingIndex);
      for (const child of node.children) {
        sortChildren(child);
      }
    }

    /**
     * Query all measurement records with their group information.
     * @param database - Opened SQLite database handle
     * @returns Array of raw record rows
     */
    function readRecords(database) {
      const rows = database.selectObjects(`
    SELECT
      r.Id           AS id,
      r.Guid         AS guid,
      r.CreatedDateTime   AS createdDateTime,
      r.ModifiedDateTime  AS modifiedDateTime,
      r.RootParameterTypeId AS rootParameterTypeId,
      g.Id           AS groupId,
      g.Guid         AS groupGuid,
      g.GivenName    AS groupName
    FROM StandardRecords r
    JOIN StandardRecordGroups g ON r.GroupId = g.Id
    ORDER BY r.Id
  `);
      return rows;
    }

    /**
     * Parse a .zmes file (Malvern Panalytical Zetasizer measurement database)
     * and return a structured representation of all records and their parameters.
     *
     * The .zmes format is a SQLite3 database used by ZS XPLORER software for
     * exporting Dynamic Light Scattering (DLS) measurement data.
     * @param data - Raw bytes of the .zmes file as an ArrayBuffer
     * @returns Parsed file with schema version, metadata, and measurement records
     * @example
     * ```ts
     * import { readFileSync } from 'node:fs';
     * import { parse } from 'zmes-parser';
     *
     * const buffer = readFileSync('measurement.zmes');
     * const result = await parse(buffer.buffer);
     * console.log(result.records[0].parameters.name);
     * ```
     */
    async function parse(data) {
      const {
        database,
        sqlite3
      } = await openDatabase(data);
      try {
        const schemaVersion = readSchemaVersion(database);
        const metadata = readStoreMetadata(database);
        const records = buildRecords(database, sqlite3);
        return {
          schemaVersion,
          metadata,
          records
        };
      } finally {
        database.close();
      }
    }
    /**
     * Read the schema version from the SchemaMeta table.
     * @param database - Opened SQLite database handle
     * @returns The current schema version number
     */
    function readSchemaVersion(database) {
      const version = database.selectValue('SELECT CurrentVersion FROM SchemaMeta LIMIT 1');
      return version ?? 0;
    }
    /**
     * Read all key-value pairs from the StoreMetadata table.
     * @param database - Opened SQLite database handle
     * @returns Record of metadata key-value pairs
     */
    function readStoreMetadata(database) {
      const rows = database.selectObjects('SELECT Key, Value FROM StoreMetadata');
      const metadata = {};
      for (const row of rows) {
        const key = row.Key;
        const value = row.Value;
        metadata[key] = value;
      }
      return metadata;
    }
    /**
     * Build all ZmesRecord objects from the database.
     * @param database - Opened SQLite database handle
     * @param sqlite3 - SQLite3 runtime
     * @returns Array of fully populated measurement records
     */
    function buildRecords(database, sqlite3) {
      const rawRecords = readRecords(database);
      const records = [];
      for (const raw of rawRecords) {
        const tree = buildParameterTree(database, raw.rootParameterTypeId);
        const parameters = readParameterData(database, sqlite3, raw.id, tree);
        records.push({
          id: raw.id,
          guid: raw.guid,
          group: {
            id: raw.groupId,
            guid: raw.groupGuid,
            ...(raw.groupName !== null ? {
              name: raw.groupName
            } : {})
          },
          createdDateTime: raw.createdDateTime,
          modifiedDateTime: raw.modifiedDateTime,
          parameters
        });
      }
      return records;
    }

    /**
     * Find a parameter by name in a flat list of children (direct children only).
     * @param children - List of parameters to search
     * @param name - Name to search for
     * @returns The matching parameter, or undefined if not found
     */
    function findParameter(children, name) {
      return children.find(child => child.name === name);
    }
    /**
     * Recursively search for a parameter by name in the parameter tree.
     * @param parameter - Root parameter node to search from
     * @param name - Name to search for
     * @returns The matching parameter, or undefined if not found
     */
    function findParameterDeep(parameter, name) {
      if (parameter.name === name) {
        return parameter;
      }
      if (parameter.children) {
        for (const child of parameter.children) {
          const found = findParameterDeep(child, name);
          if (found) {
            return found;
          }
        }
      }
      return undefined;
    }
    const VARIABLE_DESCRIPTORS = [{
      parameterName: 'Sizes',
      symbol: 'x',
      label: 'Particle diameter',
      units: 'nm',
      isDependent: false
    }, {
      parameterName: 'Particle Size Intensity Distribution',
      symbol: 'y',
      label: 'Intensity',
      units: '%',
      isDependent: true
    }, {
      parameterName: 'Particle Size Volume Distribution (%)',
      symbol: 'v',
      label: 'Volume',
      units: '%',
      isDependent: true
    }, {
      parameterName: 'Particle Size Number Distribution',
      symbol: 'n',
      label: 'Number',
      units: '%',
      isDependent: true
    }, {
      parameterName: 'Molecular Weights',
      symbol: 'w',
      label: 'Molecular weight',
      units: 'Da',
      isDependent: true
    }, {
      parameterName: 'Diffusion Coefficients',
      symbol: 'd',
      label: 'Diffusion coefficient',
      units: 'µm²/s',
      isDependent: true
    }, {
      parameterName: 'Relaxation Times',
      symbol: 'r',
      label: 'Relaxation time',
      units: 'µs',
      isDependent: true
    }, {
      parameterName: 'Form Factor',
      symbol: 'f',
      label: 'Form factor',
      units: '',
      isDependent: true
    }];
    /**
     * Parse a raw .zmes file and create an Analysis.
     *
     * Each record in the file is pushed as a spectrum with multiple variables:
     * - x: Sizes (particle diameter in nm)
     * - y: Particle Size Intensity Distribution (%)
     * - v: Particle Size Volume Distribution (%)
     * - n: Particle Size Number Distribution (%)
     * - w: Molecular Weights (Da)
     * - d: Diffusion Coefficients (µm²/s)
     * - r: Relaxation Times (µs)
     * - f: Form Factor
     *
     * Only variables present in the data are included. A record is skipped
     * if the required x (Sizes) or y (Intensity) variable is missing.
     * @param data - The raw ArrayBuffer contents of a .zmes file
     * @param options - Options for the analysis
     * @returns An Analysis containing one spectrum per record
     */
    async function fromZmes(data, options = {}) {
      const analysis = new Analysis(options);
      const zmesFile = await parse(data);
      for (const record of zmesFile.records) {
        const {
          parameters
        } = record;
        const variables = buildVariables(parameters);
        if (!variables) {
          continue;
        }
        analysis.pushSpectrum(variables, {
          id: record.guid,
          title: extractTitle(parameters),
          dataType: 'Size measurement',
          meta: extractMeta(parameters)
        });
        const spectrum = analysis.spectra.at(-1);
        if (spectrum) {
          spectrum.settings = extractSettings(parameters);
        }
      }
      return analysis;
    }
    /**
     * Build the MeasurementXYVariables object from the parameter tree.
     *
     * Returns undefined if the required x (Sizes) or y (Intensity) variable is missing.
     * @param parameters - Root parameter node
     * @returns Variables object with x, y, and optional additional variables
     */
    function buildVariables(parameters) {
      const found = new Map();
      for (const descriptor of VARIABLE_DESCRIPTORS) {
        const parameter = findParameterDeep(parameters, descriptor.parameterName);
        if (!(parameter?.value instanceof Float64Array)) {
          continue;
        }
        found.set(descriptor.symbol, {
          symbol: descriptor.symbol,
          label: descriptor.label,
          units: descriptor.units,
          data: parameter.value,
          isDependent: descriptor.isDependent
        });
      }
      const x = found.get('x');
      const y = found.get('y');
      if (!x || !y) {
        return undefined;
      }
      const variables = {
        x,
        y
      };
      for (const [key, variable] of found) {
        if (key !== 'x' && key !== 'y') {
          const letter = key;
          variables[letter] = variable;
        }
      }
      return variables;
    }
    /**
     * Extract the sample name from the parameter tree to use as title.
     * @param parameters - Root parameter node
     * @returns The sample name, or an empty string if not found
     */
    function extractTitle(parameters) {
      const sampleSettings = findParameter(parameters.children ?? [], 'Sample Settings');
      if (!sampleSettings) return '';
      const sampleName = findParameterDeep(sampleSettings, 'Sample Name');
      return typeof sampleName?.value === 'string' ? sampleName.value : '';
    }
    /**
     * Extract scalar metadata values from the parameter tree.
     * @param parameters - Root parameter node
     * @returns Record of metadata key-value pairs
     */
    function extractMeta(parameters) {
      const children = parameters.children ?? [];
      const meta = {};
      const topLevelFields = [{
        parameterName: 'Operator Name',
        metaKey: 'operatorName'
      }, {
        parameterName: 'Measurement Start Date And Time',
        metaKey: 'measurementStartDateTime'
      }, {
        parameterName: 'Measurement Completed Date And Time',
        metaKey: 'measurementCompletedDateTime'
      }, {
        parameterName: 'Repeat',
        metaKey: 'repeat'
      }, {
        parameterName: 'Number Of Repeats',
        metaKey: 'numberOfRepeats'
      }, {
        parameterName: 'Pause Between Repeats (s)',
        metaKey: 'pauseBetweenRepeats'
      }, {
        parameterName: 'Quality Indicator',
        metaKey: 'qualityIndicator'
      }, {
        parameterName: 'Result State',
        metaKey: 'resultState'
      }, {
        parameterName: 'Measurement Type',
        metaKey: 'measurementType'
      }];
      for (const field of topLevelFields) {
        const parameter = findParameter(children, field.parameterName);
        if (parameter?.value !== undefined) {
          meta[field.metaKey] = parameter.value;
        }
      }
      // Cumulants results (Z-Average, PDI)
      const deepFields = [{
        parameterName: 'Z-Average (nm)',
        metaKey: 'zAverage'
      }, {
        parameterName: 'Polydispersity Index (PI)',
        metaKey: 'polydispersityIndex'
      }, {
        parameterName: 'Derived Mean Count Rate (kcps)',
        metaKey: 'derivedMeanCountRate'
      }];
      for (const field of deepFields) {
        const parameter = findParameterDeep(parameters, field.parameterName);
        if (parameter?.value !== undefined) {
          meta[field.metaKey] = parameter.value;
        }
      }
      // Material info (search within Material Settings to avoid Core Characteristics)
      const materialSettings = findParameterDeep(parameters, 'Material Settings');
      if (materialSettings) {
        const materialRI = findParameterDeep(materialSettings, 'Material RI');
        const materialAbsorption = findParameterDeep(materialSettings, 'Material Absorption');
        if (materialRI?.value !== undefined) {
          meta.materialRI = materialRI.value;
        }
        if (materialAbsorption?.value !== undefined) {
          meta.materialAbsorption = materialAbsorption.value;
        }
      }
      // Dispersant info (from Actual Instrument Settings)
      const dispersantViscosity = findParameterDeep(parameters, 'Dispersant Viscosity (cP)');
      const dispersantRI = findParameterDeep(parameters, 'Dispersant RI');
      if (dispersantViscosity?.value !== undefined) {
        meta.dispersantViscosity = dispersantViscosity.value;
      }
      if (dispersantRI?.value !== undefined) {
        meta.dispersantRI = dispersantRI.value;
      }
      return meta;
    }
    /**
     * Extract instrument settings from the parameter tree.
     * @param parameters - Root parameter node
     * @returns Settings object with instrument info and measurement parameters
     */
    function extractSettings(parameters) {
      const children = parameters.children ?? [];
      const softwareVersion = findParameter(children, 'Software Version');
      const instrumentSerialNumber = findParameterDeep(parameters, 'Instrument Serial Number');
      const settings = {
        instrument: {
          manufacturer: 'Malvern Panalytical',
          model: 'Zetasizer',
          ...(typeof instrumentSerialNumber?.value === 'string' ? {
            serialNumber: instrumentSerialNumber.value
          } : {}),
          software: {
            name: 'ZS XPLORER',
            ...(typeof softwareVersion?.value === 'string' ? {
              version: softwareVersion.value
            } : {})
          }
        }
      };
      // Actual instrument settings
      const instrumentSettingsFields = [{
        parameterName: 'Detector Angle (°)',
        settingsKey: 'detectorAngle'
      }, {
        parameterName: 'Run Duration (s)',
        settingsKey: 'runDuration'
      }, {
        parameterName: 'Number Of Runs',
        settingsKey: 'numberOfRuns'
      }, {
        parameterName: 'Temperature (°C)',
        settingsKey: 'temperature'
      }, {
        parameterName: 'Attenuator',
        settingsKey: 'attenuator'
      }, {
        parameterName: 'Attenuation Factor',
        settingsKey: 'attenuationFactor'
      }, {
        parameterName: 'Cuvette Position (mm)',
        settingsKey: 'cuvettePosition'
      }, {
        parameterName: 'Laser Wavelength (nm)',
        settingsKey: 'laserWavelength'
      }];
      for (const field of instrumentSettingsFields) {
        const parameter = findParameterDeep(parameters, field.parameterName);
        if (typeof parameter?.value === 'number') {
          settings[field.settingsKey] = parameter.value;
        }
      }
      return settings;
    }

    exports.AnalysesManager = AnalysesManager;
    exports.Analysis = Analysis;
    exports.JSGraph = JSGraph;
    exports.fromJcamp = fromJcamp;
    exports.fromZmes = fromZmes;
    exports.toJcamp = toJcamp;
    exports.toJcamps = toJcamps;
    exports.toMatrix = toMatrix;
    exports.toText = toText;

}));
//# sourceMappingURL=dls-analysis.umd.js.map
