/**
 * mass-tools
 * @version v0.61.2
 * @link https://github.com/cheminfo/mass-tools#readme
 * @license MIT
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.MassTools = factory());
}(this, (function () { 'use strict';

  const toString$a = Object.prototype.toString;
  function isAnyArray$7(object) {
    return toString$a.call(object).endsWith('Array]');
  }

  var src$q = /*#__PURE__*/Object.freeze({
    __proto__: null,
    'default': isAnyArray$7
  });

  var commonjsGlobal$1 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

  function getAugmentedNamespace(n) {
  	if (n.__esModule) return n;
  	var a = Object.defineProperty({}, '__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;
  }

  function createCommonjsModule$1(fn) {
    var module = { exports: {} };
  	return fn(module, module.exports), module.exports;
  }

  function commonjsRequire (target) {
  	throw new Error('Could not dynamically require "' + target + '". Please configure the dynamicRequireTargets option of @rollup/plugin-commonjs appropriately for this require call to behave properly.');
  }

  var isArray$2 = /*@__PURE__*/getAugmentedNamespace(src$q);

  function _interopDefaultLegacy$5(e) {
    return e && typeof e === 'object' && 'default' in e ? e : {
      'default': e
    };
  }

  var isArray__default$4 = /*#__PURE__*/_interopDefaultLegacy$5(isArray$2);

  function max$8(input, options = {}) {
    if (!isArray__default$4['default'](input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }

    const {
      fromIndex = 0,
      toIndex = input.length
    } = options;

    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');
    }

    let maxValue = input[fromIndex];

    for (let i = fromIndex + 1; i < toIndex; i++) {
      if (input[i] > maxValue) maxValue = input[i];
    }

    return maxValue;
  }

  var lib$7 = max$8;

  function max$7(input) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    if (!isAnyArray$7(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;
  }

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

  function sum$4(input) {
    if (!isAnyArray$7(input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }

    var sumValue = 0;

    for (var i = 0; i < input.length; i++) {
      sumValue += input[i];
    }

    return sumValue;
  }

  var libEs6$1 = /*#__PURE__*/Object.freeze({
    __proto__: null,
    'default': sum$4
  });

  var max$6 = /*@__PURE__*/getAugmentedNamespace(libEs6$2);

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

  function _interopDefaultLegacy$4(e) {
    return e && typeof e === 'object' && 'default' in e ? e : {
      'default': e
    };
  }

  var isArray__default$3 = /*#__PURE__*/_interopDefaultLegacy$4(isArray$2);

  var max__default = /*#__PURE__*/_interopDefaultLegacy$4(max$6);

  var sum__default = /*#__PURE__*/_interopDefaultLegacy$4(sum$3);

  function norm(input, options = {}) {
    const {
      algorithm = 'absolute',
      sumValue = 1,
      maxValue = 1
    } = options;

    if (!isArray__default$3['default'](input)) {
      throw new Error('input must be an array');
    }

    let output;

    if (options.output !== undefined) {
      if (!isArray__default$3['default'](options.output)) {
        throw new TypeError('output option must be an array if specified');
      }

      output = options.output;
    } else {
      output = new Array(input.length);
    }

    if (input.length === 0) {
      throw new Error('input must not be empty');
    }

    switch (algorithm.toLowerCase()) {
      case 'absolute':
        {
          let absoluteSumValue = absoluteSum(input) / sumValue;
          if (absoluteSumValue === 0) return input.slice(0);

          for (let i = 0; i < input.length; i++) {
            output[i] = input[i] / absoluteSumValue;
          }

          return output;
        }

      case 'max':
        {
          let currentMaxValue = max__default['default'](input);
          if (currentMaxValue === 0) return input.slice(0);
          const factor = maxValue / currentMaxValue;

          for (let i = 0; i < input.length; i++) {
            output[i] = input[i] * factor;
          }

          return output;
        }

      case 'sum':
        {
          let sumFactor = sum__default['default'](input) / sumValue;
          if (sumFactor === 0) return input.slice(0);

          for (let i = 0; i < input.length; i++) {
            output[i] = input[i] / sumFactor;
          }

          return output;
        }

      default:
        throw new Error(`norm: unknown algorithm: ${algorithm}`);
    }
  }

  function absoluteSum(input) {
    let sumValue = 0;

    for (let i = 0; i < input.length; i++) {
      sumValue += Math.abs(input[i]);
    }

    return sumValue;
  }

  var lib$6 = norm;

  /**
   * In place modification of the 2 arrays to make X unique and sum the Y if X has the same value
   * @param {object} [points={}] : Object of points contains property x (an array) and y (an array)
   * @return points
   */
  function uniqueX(points = {}) {
    const {
      x,
      y
    } = points;
    if (x.length < 2) return;

    if (x.length !== y.length) {
      throw new Error('The X and Y arrays mush have the same length');
    }

    let current = x[0];
    let counter = 0;

    for (let i = 1; i < x.length; i++) {
      if (current !== x[i]) {
        counter++;
        current = x[i];
        x[counter] = x[i];

        if (i !== counter) {
          y[counter] = 0;
        }
      }

      if (i !== counter) {
        y[counter] += y[i];
      }
    }

    x.length = counter + 1;
    y.length = counter + 1;
  }

  /**
   * Returns true if x is monotone
   * @param {Array} array
   * @return {boolean}
   */
  function xIsMonotone$1(array) {
    if (array.length <= 2) {
      return true;
    }

    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 false;
      }

      return true;
    }

    if (array[0] < array[array.length - 1]) {
      for (let i = 0; i < array.length - 1; i++) {
        if (array[i] >= array[i + 1]) return false;
      }
    } else {
      for (let i = 0; i < array.length - 1; i++) {
        if (array[i] <= array[i + 1]) return false;
      }
    }

    return true;
  }

  function min$8(input) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    if (!isAnyArray$7(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;
  }

  const GAUSSIAN_EXP_FACTOR$2 = -4 * Math.LN2;
  const ROOT_PI_OVER_LN2$2 = Math.sqrt(Math.PI / Math.LN2);
  const ROOT_THREE$2 = Math.sqrt(3);
  const ROOT_2LN2$2 = Math.sqrt(2 * Math.LN2);
  const ROOT_2LN2_MINUS_ONE$2 = Math.sqrt(2 * Math.LN2) - 1;

  // https://en.wikipedia.org/wiki/Error_function#Inverse_functions
  // This code yields to a good approximation
  // If needed a better implementation using polynomial can be found on https://en.wikipedia.org/wiki/Error_function#Inverse_functions
  function erfinv$2(x) {
    let a = 0.147;
    if (x === 0) return 0;
    let ln1MinusXSqrd = Math.log(1 - x * x);
    let lnEtcBy2Plus2 = ln1MinusXSqrd / 2 + 2 / (Math.PI * a);
    let firstSqrt = Math.sqrt(lnEtcBy2Plus2 ** 2 - ln1MinusXSqrd / a);
    let secondSqrt = Math.sqrt(firstSqrt - lnEtcBy2Plus2);
    return secondSqrt * (x > 0 ? 1 : -1);
  }

  class Gaussian$2 {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=4*LN2/(PI*FWHM)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.sd] - Standard deviation, if it's defined options.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      this.fwhm = options.sd ? Gaussian$2.widthToFWHM(2 * options.sd) : options.fwhm ? options.fwhm : 500;
      this.height = options.height === undefined ? Math.sqrt(-GAUSSIAN_EXP_FACTOR$2 / Math.PI) / this.fwhm : options.height;
    }
    /**
     * Calculate a gaussian shape
     * @param {object} [options = {}]
     * @param {number} [options.factor = 6] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {number} [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return {Float64Array} y values
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.min(Math.ceil(this.fwhm * factor), Math.pow(2, 25) - 1);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      const data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a gaussian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @returns {number} - the y value of gaussian with the current parameters.
     */


    fct(x) {
      return Gaussian$2.fct(x, this.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999]
     * @returns {number}
     */


    getFactor(area = 0.9999) {
      return Gaussian$2.getFactor(area);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return Gaussian$2.getArea(this.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
     * //https://mathworld.wolfram.com/GaussianFunction.html
     * @param {number} width - Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      //https://mathworld.wolfram.com/GaussianFunction.html
      return Gaussian$2.widthToFWHM(width);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/GaussianFunction.html
     * @param {number} fwhm - Full Width at Half Maximum.
     * @returns {number} width
     */


    fwhmToWidth(fwhm = this.fwhm) {
      return Gaussian$2.fwhmToWidth(fwhm);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  Gaussian$2.fct = function fct(x, fwhm = 500) {
    return Math.exp(GAUSSIAN_EXP_FACTOR$2 * Math.pow(x / fwhm, 2));
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
   * //https://mathworld.wolfram.com/GaussianFunction.html
   * @param {number} width - Width between the inflection points
   * @returns {number} fwhm
   */


  Gaussian$2.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_2LN2$2;
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/GaussianFunction.html
   * @param {number} fwhm - Full Width at Half Maximum.
   * @returns {number} width
   */


  Gaussian$2.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_2LN2$2;
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {object} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Gaussian$2.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1
    } = options;
    return height * ROOT_PI_OVER_LN2$2 * fwhm / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage.
   * @param {number} [area=0.9999]
   * @returns {number}
   */


  Gaussian$2.getFactor = function getFactor(area = 0.9999) {
    return Math.sqrt(2) * erfinv$2(area);
  };

  class Lorentzian$2 {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=2/(PI*FWHM)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.sd] - Standard deviation, if it's defined options.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      this.fwhm = options.fwhm === undefined ? 500 : options.fwhm;
      this.height = options.height === undefined ? 2 / Math.PI / this.fwhm : options.height;
    }
    /**
     * Calculate a lorentzian shape
     * @param {object} [options = {}]
     * @param {number} [options.factor = Math.tan(Math.PI * (0.9999 - 0.5))] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {number} [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return {Float64Array} y values
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.min(Math.ceil(this.fwhm * factor), Math.pow(2, 25) - 1);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      const data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a lorentzian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @returns {number} - the y value of lorentzian with the current parameters.
     */


    fct(x) {
      return Lorentzian$2.fct(x, this.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999]
     * @returns {number}
     */


    getFactor(area = 0.9999) {
      return Lorentzian$2.getFactor(area);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return Lorentzian$2.getArea(this.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of width between the inflection points of a specific shape from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/LorentzianFunction.html
     * @param {number} [fwhm] - Full Width at Half Maximum.
     * @returns {number} width between the inflection points
     */


    fwhmToWidth(fwhm = this.fwhm) {
      return Lorentzian$2.fwhmToWidth(fwhm);
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) of a specific shape from the width between the inflection points.
     * //https://mathworld.wolfram.com/LorentzianFunction.html
     * @param {number} [width] Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      return Lorentzian$2.widthToFWHM(width);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  Lorentzian$2.fct = function fct(x, fwhm) {
    const squareFWHM = fwhm * fwhm;
    return squareFWHM / (4 * Math.pow(x, 2) + squareFWHM);
  };
  /**
   * Compute the value of width between the inflection points of a specific shape from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/LorentzianFunction.html
   * @param {number} [fwhm] - Full Width at Half Maximum.
   * @returns {number} width between the inflection points
   */


  Lorentzian$2.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_THREE$2;
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) of a specific shape from the width between the inflection points.
   * //https://mathworld.wolfram.com/LorentzianFunction.html
   * @param {number} [width] Width between the inflection points
   * @returns {number} fwhm
   */


  Lorentzian$2.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_THREE$2;
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {*} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Lorentzian$2.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1
    } = options;
    return height * Math.PI * fwhm / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage
   * @param {number} [area=0.9999]
   * @returns {number}
   */


  Lorentzian$2.getFactor = function getFactor(area = 0.9999) {
    return 2 * Math.tan(Math.PI * (area - 0.5));
  };

  class PseudoVoigt$2 {
    /**
     * @param {object} [options={}]
     * @param {number} [options.height=1/(mu*FWHM/sqrt(4*LN2/PI)+(1-mu)*fwhm*PI*0.5)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm=500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.mu=0.5] - ratio of gaussian contribution.
     */
    constructor(options = {}) {
      this.mu = options.mu === undefined ? 0.5 : options.mu;
      this.fwhm = options.fwhm === undefined ? 500 : options.fwhm;
      this.height = options.height === undefined ? 1 / (this.mu / Math.sqrt(-GAUSSIAN_EXP_FACTOR$2 / Math.PI) * this.fwhm + (1 - this.mu) * this.fwhm * Math.PI / 2) : options.height;
    }
    /**
     * Calculate a linear combination of gaussian and lorentzian function width an same full width at half maximum
     * @param { object } [options = {}]
     * @param { number } [options.factor = 2 * Math.tan(Math.PI * (0.9999 - 0.5))] - Number of time to take fwhm in the calculation of the length.Default covers 99.99 % of area.
     * @param { number } [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return { object } - { fwhm, data<Float64Array>} - An with the number of points at half maximum and the array of y values covering the 99.99 % of the area.
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.ceil(this.fwhm * factor);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      let data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a linear combination of Gaussian and Lorentzian shapes where the full width at half maximum are the same for both kind of shapes (see README for equation).
     * @param {number} [x] x value to calculate.
     * @returns {number} - the y value of a pseudo voigt with the current parameters.
     */


    fct(x) {
      return PseudoVoigt$2.fct(x, this.fwhm, this.mu);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999] - required area to be coverage
     * @param {number} [mu=this.mu] - ratio of gaussian contribution.
     * @returns {number}
     */


    getFactor(area = 0.9999, mu = this.mu) {
      return PseudoVoigt$2.getFactor(area, mu);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return PseudoVoigt$2.getArea(this.fwhm, {
        height: this.height,
        mu: this.mu
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FMHM) from width between the inflection points.
     * @param {number} width - width between the inflection points
     * @param {number} [mu = 0.5] - ratio of gaussian contribution.
     * @returns {number} Full Width at Half Maximum (FMHM).
     */


    widthToFWHM(width, mu) {
      return PseudoVoigt$2.widthToFWHM(width, mu);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * @param {number} fwhm - Full Width at Half Maximum.
     * @param {number} [mu] - ratio of gaussian contribution.
     * @returns {number} width between the inflection points.
     */


    fwhmToWidth(fwhm = this.fwhm, mu = this.mu) {
      return PseudoVoigt$2.fwhmToWidth(fwhm, mu);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }
    /**
     * set a new mu
     * @param {number} mu - ratio of gaussian contribution.
     */


    setMu(mu) {
      this.mu = mu;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @param {number} [mu=0.5] - ratio of gaussian contribution.
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  PseudoVoigt$2.fct = function fct(x, fwhm, mu = 0.5) {
    return (1 - mu) * Lorentzian$2.fct(x, fwhm) + mu * Gaussian$2.fct(x, fwhm);
  };
  /**
   * Compute the value of Full Width at Half Maximum (FMHM) from width between the inflection points.
   * @param {number} width - width between the inflection points
   * @param {number} [mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} Full Width at Half Maximum (FMHM).
   */


  PseudoVoigt$2.widthToFWHM = function widthToFWHM(width, mu = 0.5) {
    return width * (mu * ROOT_2LN2_MINUS_ONE$2 + 1);
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * @param {number} fwhm - Full Width at Half Maximum.
   * @param {number} [mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} width between the inflection points.
   */


  PseudoVoigt$2.fwhmToWidth = function fwhmToWidth(fwhm, mu = 0.5) {
    return fwhm / (mu * ROOT_2LN2_MINUS_ONE$2 + 1);
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {*} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @param {number} [options.mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  PseudoVoigt$2.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1,
      mu = 0.5
    } = options;
    return fwhm * height * (mu * ROOT_PI_OVER_LN2$2 + (1 - mu) * Math.PI) / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage
   * @param {number} [area=0.9999] - required area to be coverage
   * @param {number} [mu=this.mu] - ratio of gaussian contribution.
   * @returns {number}
   */


  PseudoVoigt$2.getFactor = function getFactor(area = 0.9999, mu = 0.5) {
    return mu < 1 ? Lorentzian$2.getFactor(area) : Gaussian$2.getFactor(area);
  };

  let axis$2 = ['x', 'y'];
  class Gaussian2D$2 {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=4*LN2/(PI*xFWHM*yFWHM)] Define the height of the peak, by default area=1 (normalized).
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM used if x or y has not the fwhm property.
     * @param {object} [options.x] - Options for x axis.
     * @param {number} [options.x.fwhm = fwhm] - Full Width at Half Maximum in the number of points in FWHM for x axis.
     * @param {number} [options.x.sd] - Standard deviation for x axis, if it's defined options.x.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     * @param {object} [options.y] - Options for y axis.
     * @param {number} [options.y.fwhm = fwhm] - Full Width at Half Maximum in the number of points in FWHM for y axis.
     * @param {number} [options.y.sd] - Standard deviation for y axis, if it's defined options.y.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      let {
        fwhm: globalFWHM = 500
      } = options;

      for (let i of axis$2) {
        let fwhm;

        if (!options[i]) {
          fwhm = globalFWHM;
        } else {
          fwhm = options[i].sd ? Gaussian2D$2.widthToFWHM(2 * options[i].sd) : options[i].fwhm || globalFWHM;
        }

        this[i] = {
          fwhm
        };
      }

      this.height = options.height === undefined ? -GAUSSIAN_EXP_FACTOR$2 / Math.PI / this.x.fwhm / this.y.fwhm : options.height;
    }
    /**
     * Calculate a Gaussian2D shape
     * @param {object} [options = {}]
     * @param {number} [options.factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {object} [options.x] - parameter for x axis.
     * @param {number} [options.x.length=fwhm*factor+1] - length on x axis.
     * @param {number} [options.x.factor=factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {object} [options.y] - parameter for y axis.
     * @param {number} [options.y.length=fwhm*factor+1] - length on y axis.
     * @param {number} [options.y.factor=factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @return {Array<Float64Array>} - z values.
     */


    getData(options = {}) {
      let {
        x = {},
        y = {},
        factor = this.getFactor(),
        length
      } = options;
      let xLength = x.length || length;

      if (!xLength) {
        let {
          factor: xFactor = factor
        } = x;
        xLength = Math.min(Math.ceil(this.x.fwhm * xFactor), Math.pow(2, 25) - 1);
        if (xLength % 2 === 0) xLength++;
      }

      let yLength = y.length || length;

      if (!yLength) {
        let {
          factor: yFactor = factor
        } = y;
        yLength = Math.min(Math.ceil(this.y.fwhm * yFactor), Math.pow(2, 25) - 1);
        if (yLength % 2 === 0) yLength++;
      }

      const xCenter = (xLength - 1) / 2;
      const yCenter = (yLength - 1) / 2;
      const data = new Array(xLength);

      for (let i = 0; i < xLength; i++) {
        data[i] = new Array(yLength);
      }

      for (let i = 0; i < xLength; i++) {
        for (let j = 0; j < yLength; j++) {
          data[i][j] = this.fct(i - xCenter, j - yCenter) * this.height;
        }
      }

      return data;
    }
    /**
     * Return the intensity value of a 2D gaussian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @param {number} y - y value to calculate.
     * @returns {number} - the z value of bi-dimensional gaussian with the current parameters.
     */


    fct(x, y) {
      return Gaussian2D$2.fct(x, y, this.x.fwhm, this.y.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific volume coverage.
     * @param {number} [volume=0.9999]
     * @returns {number}
     */


    getFactor(volume = 0.9999) {
      return Gaussian2D$2.getFactor(volume);
    }
    /**
     * Calculate the volume of the shape.
     * @returns {number} - returns the volume.
     */


    getVolume() {
      return Gaussian2D$2.getVolume(this.x.fwhm, this.y.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
     * //https://mathworld.wolfram.com/Gaussian2DFunction.html
     * @param {number} width - Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      //https://mathworld.wolfram.com/Gaussian2DFunction.html
      return Gaussian2D$2.widthToFWHM(width);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/Gaussian2DFunction.html
     * @param {number} fwhm - Full Width at Half Maximum.
     * @returns {number} width
     */


    fwhmToWidth(fwhm = this.x.fwhm) {
      return Gaussian2D$2.fwhmToWidth(fwhm);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     * @param {string|Array<string>} axisLabel - label of axis, if it is undefined fwhm is set to both axis.
     */


    setFWHM(fwhm, axisLabel) {
      if (!axisLabel) axisLabel = axis$2;
      if (!Array.isArray(axisLabel)) axisLabel = [axisLabel];

      for (let i of axisLabel) {
        let axisName = i.toLowerCase();

        if (axisName !== 'y' && axisName !== 'x') {
          throw new Error('axis label should be x or y');
        }

        this[axisName].fwhm = fwhm;
      }
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a Gaussian2D shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} y - y value to calculate.
   * @param {number} fwhmX - full width half maximum in the x axis.
   * @param {number} fwhmY - full width half maximum in the y axis.
   * @returns {number} - the z value of bi-dimensional gaussian with the current parameters.
   */

  Gaussian2D$2.fct = function fct(x, y, xFWHM = 500, yFWHM = 500) {
    return Math.exp(GAUSSIAN_EXP_FACTOR$2 * (Math.pow(x / xFWHM, 2) + Math.pow(y / yFWHM, 2)));
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
   * //https://mathworld.wolfram.com/Gaussian2DFunction.html
   * @param {number} width - Width between the inflection points
   * @returns {number} fwhm
   */


  Gaussian2D$2.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_2LN2$2;
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/Gaussian2DFunction.html
   * @param {number} fwhm - Full Width at Half Maximum.
   * @returns {number} width
   */


  Gaussian2D$2.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_2LN2$2;
  };
  /**
   * Calculate the volume of a specific shape.
   * @param {number} xFWHM - Full width at half maximum for x axis.
   * @param {number} yFWHM - Full width at half maximum for y axis.
   * @param {object} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum z value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Gaussian2D$2.getVolume = function getVolume(xFWHM, yFWHM, options = {}) {
    let {
      height = 1
    } = options;
    return height * Math.PI * xFWHM * yFWHM / Math.LN2 / 4;
  };
  /**@TODO look for a better factor
   * Calculate the number of times FWHM allows to reach a specific volume coverage.
   * @param {number} [volume=0.9999]
   * @returns {number}
   */


  Gaussian2D$2.getFactor = function getFactor(volume = 0.9999) {
    return Math.sqrt(2) * erfinv$2(volume);
  };

  function getShapeGenerator$2(options) {
    let {
      kind = 'Gaussian',
      options: shapeOptions
    } = options;

    switch (kind.toLowerCase().replace(/[^a-z^0-9]/g, '')) {
      case 'gaussian':
        return new Gaussian$2(shapeOptions);

      case 'lorentzian':
        return new Lorentzian$2(shapeOptions);

      case 'pseudovoigt':
        return new PseudoVoigt$2(shapeOptions);

      case 'gaussian2d':
        return new Gaussian2D$2(shapeOptions);

      default:
        throw new Error(`Unknown kind: ${kind}`);
    }
  }

  /**
   * Apply Savitzky Golay algorithm
   * @param {array} [ys] Array of y values
   * @param {array|number} [xs] Array of X or deltaX
   * @param {object} [options={}]
   * @param {number} [options.windowSize=9]
   * @param {number} [options.derivative=0]
   * @param {number} [options.polynomial=3]
   * @return {array} Array containing the new ys (same length)
   */
  function SavitzkyGolay$1(ys, xs, options = {}) {
    let {
      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 (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');
    }

    let half = Math.floor(windowSize / 2);
    let np = ys.length;
    let ans = new Array(np);
    let weights = fullWeights$1(windowSize, polynomial, derivative);
    let hs = 0;
    let constantH = true;

    if (Array.isArray(xs)) {
      constantH = false;
    } else {
      hs = Math.pow(xs, derivative);
    } //For the borders


    for (let i = 0; i < half; i++) {
      let wg1 = weights[half - i - 1];
      let 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$1(xs, half - i - 1, half, derivative);
        ans[half - i - 1] = d1 / hs;
        hs = getHs$1(xs, np - half + i, half, derivative);
        ans[np - half + i] = d2 / hs;
      }
    } //For the internal points


    let 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$1(xs, i - half - 1, half, derivative);
      ans[i - half - 1] = d / hs;
    }

    return ans;
  }

  function getHs$1(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 Math.pow(hs / count, derivative);
  }

  function GramPoly$1(i, m, k, s) {
    let Grampoly = 0;

    if (k > 0) {
      Grampoly = (4 * k - 2) / (k * (2 * m - k + 1)) * (i * GramPoly$1(i, m, k - 1, s) + s * GramPoly$1(i, m, k - 1, s - 1)) - (k - 1) * (2 * m + k) / (k * (2 * m - k + 1)) * GramPoly$1(i, m, k - 2, s);
    } else {
      if (k === 0 && s === 0) {
        Grampoly = 1;
      } else {
        Grampoly = 0;
      }
    }

    return Grampoly;
  }

  function GenFact$1(a, b) {
    let gf = 1;

    if (a >= b) {
      for (let j = a - b + 1; j <= a; j++) {
        gf *= j;
      }
    }

    return gf;
  }

  function Weight$1(i, t, m, n, s) {
    let sum = 0;

    for (let k = 0; k <= n; k++) {
      //console.log(k);
      sum += (2 * k + 1) * (GenFact$1(2 * m, k) / GenFact$1(2 * m + k + 1, k + 1)) * GramPoly$1(i, m, k, 0) * GramPoly$1(t, m, k, s);
    }

    return sum;
  }
  /**
   *
   * @param m  Number of points
   * @param n  Polynomial grade
   * @param s  Derivative
   */


  function fullWeights$1(m, n, s) {
    let weights = new Array(m);
    let np = Math.floor(m / 2);

    for (let t = -np; t <= np; t++) {
      weights[t + np] = new Array(m);

      for (let j = -np; j <= np; j++) {
        weights[t + np][j + np] = Weight$1(j, t, np, n, s);
      }
    }

    return weights;
  }
  /*function entropy(data,h,options){
      var trend = SavitzkyGolay(data,h,trendOptions);
      var copy = new Array(data.length);
      var sum = 0;
      var max = 0;
      for(var i=0;i<data.length;i++){
          copy[i] = data[i]-trend[i];
      }

      sum/=data.length;
      console.log(sum+" "+max);
      console.log(stat.array.standardDeviation(copy));
      console.log(Math.abs(stat.array.mean(copy))/stat.array.standardDeviation(copy));
      return sum;

  }



  function guessWindowSize(data, h){
      console.log("entropy "+entropy(data,h,trendOptions));
      return 5;
  }
  */

  /**
   * Global spectra deconvolution
   * @param {object} data - Object data with x and y arrays
   * @param {Array<number>} [data.x] - Independent variable
   * @param {Array<number>} [data.y] - Dependent variable
   * @param {object} [options={}] - Options object
   * @param {object} [options.shape={}] - Object that specified the kind of shape to calculate the FWHM instead of width between inflection points. see https://mljs.github.io/peak-shape-generator/#inflectionpointswidthtofwhm
   * @param {object} [options.shape.kind='gaussian']
   * @param {object} [options.shape.options={}]
   * @param {object} [options.sgOptions] - Options object for Savitzky-Golay filter. See https://github.com/mljs/savitzky-golay-generalized#options
   * @param {number} [options.sgOptions.windowSize = 9] - points to use in the approximations
   * @param {number} [options.sgOptions.polynomial = 3] - degree of the polynomial to use in the approximations
   * @param {number} [options.minMaxRatio = 0.00025] - Threshold to determine if a given peak should be considered as a noise
   * @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.
   * @param {number} [options.noiseLevel = 0] - Noise threshold in spectrum units
   * @param {boolean} [options.maxCriteria = true] - Peaks are local maximum(true) or minimum(false)
   * @param {boolean} [options.smoothY = true] - Select the peak intensities from a smoothed version of the independent variables
   * @param {boolean} [options.realTopDetection = false] - Use a quadratic optimizations with the peak and its 3 closest neighbors
   * to determine the true x,y values of the peak?
   * @param {number} [options.heightFactor = 0] - Factor to multiply the calculated height (usually 2)
   * @param {number} [options.derivativeThreshold = -1] - Filters based on the amplitude of the first derivative
   * @return {Array<object>}
   */

  function gsd$2(data, options = {}) {
    let {
      noiseLevel,
      sgOptions = {
        windowSize: 9,
        polynomial: 3
      },
      shape = {},
      smoothY = true,
      heightFactor = 0,
      broadRatio = 0.0,
      maxCriteria = true,
      minMaxRatio = 0.00025,
      derivativeThreshold = -1,
      realTopDetection = false
    } = options;
    let {
      y: yIn,
      x
    } = data;
    const y = yIn.slice();
    let equalSpaced = isEqualSpaced$1(x);

    if (noiseLevel === undefined) {
      noiseLevel = equalSpaced ? getNoiseLevel$1(y) : 0;
    }

    const yCorrection = {
      m: 1,
      b: noiseLevel
    };

    if (!maxCriteria) {
      yCorrection.m = -1;
      yCorrection.b *= -1;
    }

    for (let i = 0; i < y.length; i++) {
      y[i] = yCorrection.m * y[i] - yCorrection.b;
    }

    for (let i = 0; i < y.length; i++) {
      if (y[i] < 0) {
        y[i] = 0;
      }
    } // If the max difference between delta x is less than 5%, then,
    // we can assume it to be equally spaced variable


    let yData = y;
    let dY, ddY;
    const {
      windowSize,
      polynomial
    } = sgOptions;

    if (equalSpaced) {
      if (smoothY) {
        yData = SavitzkyGolay$1(y, x[1] - x[0], {
          windowSize,
          polynomial,
          derivative: 0
        });
      }

      dY = SavitzkyGolay$1(y, x[1] - x[0], {
        windowSize,
        polynomial,
        derivative: 1
      });
      ddY = SavitzkyGolay$1(y, x[1] - x[0], {
        windowSize,
        polynomial,
        derivative: 2
      });
    } else {
      if (smoothY) {
        yData = SavitzkyGolay$1(y, x, {
          windowSize,
          polynomial,
          derivative: 0
        });
      }

      dY = SavitzkyGolay$1(y, x, {
        windowSize,
        polynomial,
        derivative: 1
      });
      ddY = SavitzkyGolay$1(y, x, {
        windowSize,
        polynomial,
        derivative: 2
      });
    }

    const xData = x;
    const dX = x[1] - x[0];
    let maxDdy = 0;
    let maxY = 0;

    for (let i = 0; i < yData.length; i++) {
      if (Math.abs(ddY[i]) > maxDdy) {
        maxDdy = Math.abs(ddY[i]);
      }

      if (Math.abs(yData[i]) > maxY) {
        maxY = Math.abs(yData[i]);
      }
    }

    let lastMax = null;
    let lastMin = null;
    let minddY = [];
    let intervalL = [];
    let intervalR = [];
    let broadMask = []; // By the intermediate value theorem We cannot find 2 consecutive maximum or minimum

    for (let i = 1; i < yData.length - 1; ++i) {
      // filter based on derivativeThreshold
      // console.log('pasa', y[i], dY[i], ddY[i]);
      if (Math.abs(dY[i]) > derivativeThreshold) {
        // Minimum in first derivative
        if (dY[i] < dY[i - 1] && dY[i] <= dY[i + 1] || dY[i] <= dY[i - 1] && dY[i] < dY[i + 1]) {
          lastMin = {
            x: xData[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: xData[i],
            index: i
          };

          if (dX < 0 && lastMin !== null) {
            intervalL.push(lastMax);
            intervalR.push(lastMin);
          }
        }
      } // Minimum in second derivative


      if (ddY[i] < ddY[i - 1] && ddY[i] < ddY[i + 1]) {
        minddY.push(i);
        broadMask.push(Math.abs(ddY[i]) <= broadRatio * maxDdy);
      }
    }

    let widthProcessor = shape.kind ? getShapeGenerator$2(shape.kind, shape.options).widthToFWHM : x => x;
    let signals = [];
    let lastK = -1;
    let possible, frequency, distanceJ, minDistance, gettingCloser;

    for (let j = 0; j < minddY.length; ++j) {
      frequency = xData[minddY[j]];
      possible = -1;
      let k = lastK + 1;
      minDistance = Number.MAX_VALUE;
      distanceJ = 0;
      gettingCloser = true;

      while (possible === -1 && k < intervalL.length && gettingCloser) {
        distanceJ = Math.abs(frequency - (intervalL[k].x + intervalR[k].x) / 2); // Still getting closer?

        if (distanceJ < minDistance) {
          minDistance = distanceJ;
        } else {
          gettingCloser = false;
        }

        if (distanceJ < Math.abs(intervalL[k].x - intervalR[k].x) / 2) {
          possible = k;
          lastK = k;
        }

        ++k;
      }

      if (possible !== -1) {
        if (Math.abs(yData[minddY[j]]) > minMaxRatio * maxY) {
          let width = Math.abs(intervalR[possible].x - intervalL[possible].x);
          signals.push({
            index: minddY[j],
            x: frequency,
            y: (yData[minddY[j]] + yCorrection.b) / yCorrection.m,
            width: widthProcessor(width),
            soft: broadMask[j]
          });
          signals[signals.length - 1].left = intervalL[possible];
          signals[signals.length - 1].right = intervalR[possible];

          if (heightFactor) {
            let yLeft = yData[intervalL[possible].index];
            let yRight = yData[intervalR[possible].index];
            signals[signals.length - 1].height = heightFactor * (signals[signals.length - 1].y - (yLeft + yRight) / 2);
          }
        }
      }
    }

    if (realTopDetection) {
      determineRealTop$1(signals, xData, yData);
    } // Correct the values to fit the original spectra data


    for (let j = 0; j < signals.length; j++) {
      signals[j].base = noiseLevel;
    }

    signals.sort(function (a, b) {
      return a.x - b.x;
    });
    return signals;
  }

  const isEqualSpaced$1 = x => {
    let tmp;
    let maxDx = 0;
    let minDx = Number.MAX_SAFE_INTEGER;

    for (let i = 0; i < x.length - 1; ++i) {
      tmp = Math.abs(x[i + 1] - x[i]);

      if (tmp < minDx) {
        minDx = tmp;
      }

      if (tmp > maxDx) {
        maxDx = tmp;
      }
    }

    return (maxDx - minDx) / maxDx < 0.05;
  };

  const getNoiseLevel$1 = y => {
    let mean = 0;
    let stddev = 0;
    let length = y.length;

    for (let i = 0; i < length; ++i) {
      mean += y[i];
    }

    mean /= length;
    let averageDeviations = new Array(length);

    for (let i = 0; i < length; ++i) {
      averageDeviations[i] = Math.abs(y[i] - mean);
    }

    averageDeviations.sort((a, b) => a - b);

    if (length % 2 === 1) {
      stddev = averageDeviations[(length - 1) / 2] / 0.6745;
    } else {
      stddev = 0.5 * (averageDeviations[length / 2] + averageDeviations[length / 2 - 1]) / 0.6745;
    }

    return stddev;
  };

  const determineRealTop$1 = (peakList, x, y) => {
    let alpha, beta, gamma, p, currentPoint;

    for (let j = 0; j < peakList.length; j++) {
      currentPoint = peakList[j].index; // peakList[j][2];
      // The detected peak could be moved 1 or 2 units to left or right.

      if (y[currentPoint - 1] >= y[currentPoint - 2] && y[currentPoint - 1] >= y[currentPoint]) {
        currentPoint--;
      } else {
        if (y[currentPoint + 1] >= y[currentPoint] && y[currentPoint + 1] >= y[currentPoint + 2]) {
          currentPoint++;
        } else {
          if (y[currentPoint - 2] >= y[currentPoint - 3] && y[currentPoint - 2] >= y[currentPoint - 1]) {
            currentPoint -= 2;
          } else {
            if (y[currentPoint + 2] >= y[currentPoint + 1] && y[currentPoint + 2] >= y[currentPoint + 3]) {
              currentPoint += 2;
            }
          }
        }
      } // interpolation to a sin() function


      if (y[currentPoint - 1] > 0 && y[currentPoint + 1] > 0 && y[currentPoint] >= y[currentPoint - 1] && y[currentPoint] >= y[currentPoint + 1] && (y[currentPoint] !== y[currentPoint - 1] || y[currentPoint] !== y[currentPoint + 1])) {
        alpha = 20 * Math.log10(y[currentPoint - 1]);
        beta = 20 * Math.log10(y[currentPoint]);
        gamma = 20 * Math.log10(y[currentPoint + 1]);
        p = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma); // console.log(alpha, beta, gamma, `p: ${p}`);
        // console.log(x[currentPoint]+" "+tmp+" "+currentPoint);

        peakList[j].x = x[currentPoint] + (x[currentPoint] - x[currentPoint - 1]) * p;
        peakList[j].y = y[currentPoint] - 0.25 * (y[currentPoint - 1] - y[currentPoint + 1]) * p;
      }
    }
  };

  /*!
   * assign-symbols <https://github.com/jonschlinkert/assign-symbols>
   *
   * Copyright (c) 2015-present, Jon Schlinkert.
   * Licensed under the MIT License.
   */

  const toString$9 = Object.prototype.toString;
  const isEnumerable = Object.prototype.propertyIsEnumerable;
  const getSymbols = Object.getOwnPropertySymbols;

  var assignSymbols = (target, ...args) => {
    if (!isObject$1(target)) {
      throw new TypeError('expected the first argument to be an object');
    }

    if (args.length === 0 || typeof Symbol !== 'function' || typeof getSymbols !== 'function') {
      return target;
    }

    for (let arg of args) {
      let names = getSymbols(arg);

      for (let key of names) {
        if (isEnumerable.call(arg, key)) {
          target[key] = arg[key];
        }
      }
    }

    return target;
  };

  function isObject$1(val) {
    return typeof val === 'function' || toString$9.call(val) === '[object Object]' || Array.isArray(val);
  }

  /*!
   * assign-deep <https://github.com/jonschlinkert/assign-deep>
   *
   * Copyright (c) 2017-present, Jon Schlinkert.
   * Released under the MIT License.
   */
  var assignDeep = createCommonjsModule$1(function (module) {

    const toString = Object.prototype.toString;

    const isValidKey = key => {
      return key !== '__proto__' && key !== 'constructor' && key !== 'prototype';
    };

    const assign = module.exports = (target, ...args) => {
      let i = 0;
      if (isPrimitive(target)) target = args[i++];
      if (!target) target = {};

      for (; i < args.length; i++) {
        if (isObject(args[i])) {
          for (const key of Object.keys(args[i])) {
            if (isValidKey(key)) {
              if (isObject(target[key]) && isObject(args[i][key])) {
                assign(target[key], args[i][key]);
              } else {
                target[key] = args[i][key];
              }
            }
          }

          assignSymbols(target, args[i]);
        }
      }

      return target;
    };

    function isObject(val) {
      return typeof val === 'function' || toString.call(val) === '[object Object]';
    }

    function isPrimitive(val) {
      return typeof val === 'object' ? val === null : typeof val !== 'function';
    }
  });

  /**
   * This function calculates the spectrum as a sum of linear combination of gaussian and lorentzian functions. The pseudo voigt
   * parameters are divided in 4 batches. 1st: centers; 2nd: heights; 3th: widths; 4th: mu's ;
   * @param t Ordinate value
   * @param p Lorentzian parameters
   * @returns {*}
   */

  function sumOfGaussianLorentzians(p) {
    return function (t) {
      let nL = p.length / 4;
      let result = 0;

      for (let i = 0; i < nL; i++) {
        result += p[i + nL] * PseudoVoigt$2.fct(t - p[i], p[i + nL * 2], p[i + nL * 3]);
      }

      return result;
    };
  }

  /**
   * This function calculates the spectrum as a sum of gaussian functions. The Gaussian
   * parameters are divided in 3 batches. 1st: centers; 2nd: height; 3th: widths;
   * @param t Ordinate values
   * @param p Gaussian parameters
   * @returns {*}
   */

  function sumOfGaussians(p) {
    return function (t) {
      let nL = p.length / 3;
      let result = 0;

      for (let i = 0; i < nL; i++) {
        result += p[i + nL] * Gaussian$2.fct(t - p[i], p[i + nL * 2]);
      }

      return result;
    };
  }

  /**
   * This function calculates the spectrum as a sum of lorentzian functions. The Lorentzian
   * parameters are divided in 3 batches. 1st: centers; 2nd: heights; 3th: widths;
   * @param t Ordinate values
   * @param p Lorentzian parameters
   * @returns {*}
   */

  function sumOfLorentzians(p) {
    return function (t) {
      let nL = p.length / 3;
      let result = 0;

      for (let i = 0; i < nL; i++) {
        result += p[i + nL] * Lorentzian$2.fct(t - p[i], p[i + nL * 2]);
      }

      return result;
    };
  }

  function checkInput(data, peaks, options) {
    let {
      shape = {
        kind: 'gaussian'
      },
      optimization = {
        kind: 'lm'
      }
    } = options;

    if (typeof shape.kind !== 'string') {
      throw new Error('kind should be a string');
    }

    let kind = shape.kind.toLowerCase().replace(/[^a-z]/g, '');
    let paramsFunc;
    let defaultParameters;

    switch (kind) {
      case 'gaussian':
        paramsFunc = sumOfGaussians;
        defaultParameters = {
          x: {
            init: peak => peak.x,
            max: peak => peak.x + peak.width * 2,
            min: peak => peak.x - peak.width * 2,
            gradientDifference: peak => peak.width * 2e-3
          },
          y: {
            init: peak => peak.y,
            max: () => 1.5,
            min: () => 0,
            gradientDifference: () => 1e-3
          },
          width: {
            init: peak => peak.width,
            max: peak => peak.width * 4,
            min: peak => peak.width * 0.25,
            gradientDifference: peak => peak.width * 2e-3
          }
        };
        break;

      case 'lorentzian':
        paramsFunc = sumOfLorentzians;
        defaultParameters = {
          x: {
            init: peak => peak.x,
            max: peak => peak.x + peak.width * 2,
            min: peak => peak.x - peak.width * 2,
            gradientDifference: peak => peak.width * 2e-3
          },
          y: {
            init: peak => peak.y,
            max: () => 1.5,
            min: () => 0,
            gradientDifference: () => 1e-3
          },
          width: {
            init: peak => peak.width,
            max: peak => peak.width * 4,
            min: peak => peak.width * 0.25,
            gradientDifference: peak => peak.width * 2e-3
          }
        };
        break;

      case 'pseudovoigt':
        paramsFunc = sumOfGaussianLorentzians;
        defaultParameters = {
          x: {
            init: peak => peak.x,
            max: peak => peak.x + peak.width * 2,
            min: peak => peak.x - peak.width * 2,
            gradientDifference: peak => peak.width * 2e-3
          },
          y: {
            init: peak => peak.y,
            max: () => 1.5,
            min: () => 0,
            gradientDifference: () => 1e-3
          },
          width: {
            init: peak => peak.width,
            max: peak => peak.width * 4,
            min: peak => peak.width * 0.25,
            gradientDifference: peak => peak.width * 2e-3
          },
          mu: {
            init: peak => peak.mu !== undefined ? peak.mu : 0.5,
            min: () => 0,
            max: () => 1,
            gradientDifference: () => 0.01
          }
        };
        break;

      default:
        throw new Error('kind of shape is not supported');
    }

    let x = data.x;
    let maxY = max$7(data.y);
    let y = new Array(x.length);

    for (let i = 0; i < x.length; i++) {
      y[i] = data.y[i] / maxY;
    }

    for (let i = 0; i < peaks.length; i++) {
      peaks[i].y /= maxY;
    }

    let parameters = assignDeep({}, optimization.parameters, defaultParameters);

    for (let key in parameters) {
      for (let par in parameters[key]) {
        if (!Array.isArray(parameters[key][par])) {
          parameters[key][par] = [parameters[key][par]];
        }

        if (parameters[key][par].length !== 1 && parameters[key][par].length !== peaks.length) {
          throw new Error(`The length of ${key}-${par} is not correct`);
        }

        for (let index = 0; index < parameters[key][par].length; index++) {
          if (typeof parameters[key][par][index] === 'number') {
            let value = parameters[key][par][index];

            parameters[key][par][index] = () => value;
          }
        }
      }
    }

    optimization.parameters = parameters;
    return {
      y,
      x,
      maxY,
      peaks,
      paramsFunc,
      optimization
    };
  }

  function checkOptions$1(data, parameterizedFunction, options) {
    let {
      timeout,
      minValues,
      maxValues,
      initialValues,
      weights = 1,
      damping = 1e-2,
      dampingStepUp = 11,
      dampingStepDown = 9,
      maxIterations = 100,
      errorTolerance = 1e-7,
      centralDifference = false,
      gradientDifference = 10e-2,
      improvementThreshold = 1e-3
    } = options;

    if (damping <= 0) {
      throw new Error('The damping option must be a positive number');
    } else if (!data.x || !data.y) {
      throw new Error('The data parameter must have x and y elements');
    } else if (!isAnyArray$7(data.x) || data.x.length < 2 || !isAnyArray$7(data.y) || data.y.length < 2) {
      throw new Error('The data parameter elements must be an array with more than 2 points');
    } else if (data.x.length !== data.y.length) {
      throw new Error('The data parameter elements must have the same size');
    }

    let parameters = initialValues || new Array(parameterizedFunction.length).fill(1);
    let nbPoints = data.y.length;
    let parLen = parameters.length;
    maxValues = maxValues || new Array(parLen).fill(Number.MAX_SAFE_INTEGER);
    minValues = minValues || new Array(parLen).fill(Number.MIN_SAFE_INTEGER);

    if (maxValues.length !== minValues.length) {
      throw new Error('minValues and maxValues must be the same size');
    }

    if (!isAnyArray$7(parameters)) {
      throw new Error('initialValues must be an array');
    }

    if (typeof gradientDifference === 'number') {
      gradientDifference = new Array(parameters.length).fill(gradientDifference);
    } else if (isAnyArray$7(gradientDifference)) {
      if (gradientDifference.length !== parLen) {
        gradientDifference = new Array(parLen).fill(gradientDifference[0]);
      }
    } else {
      throw new Error('gradientDifference should be a number or array with length equal to the number of parameters');
    }

    let filler;

    if (typeof weights === 'number') {
      let value = 1 / weights ** 2;

      filler = () => value;
    } else if (isAnyArray$7(weights)) {
      if (weights.length < data.x.length) {
        let value = 1 / weights[0] ** 2;

        filler = () => value;
      } else {
        filler = i => 1 / weights[i] ** 2;
      }
    } else {
      throw new Error('weights should be a number or array with length equal to the number of data points');
    }

    let checkTimeout;

    if (timeout !== undefined) {
      if (typeof timeout !== 'number') {
        throw new Error('timeout should be a number');
      }

      let endTime = Date.now() + timeout * 1000;

      checkTimeout = () => Date.now() > endTime;
    } else {
      checkTimeout = () => false;
    }

    let weightSquare = new Array(data.x.length);

    for (let i = 0; i < nbPoints; i++) {
      weightSquare[i] = filler(i);
    }

    return {
      checkTimeout,
      minValues,
      maxValues,
      parameters,
      weightSquare,
      damping,
      dampingStepUp,
      dampingStepDown,
      maxIterations,
      errorTolerance,
      centralDifference,
      gradientDifference,
      improvementThreshold
    };
  }

  /**
   * the sum of the weighted squares of the errors (or weighted residuals) between the data.y
   * and the curve-fit function.
   * @ignore
   * @param {{x:Array<number>, y:Array<number>}} data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ]
   * @param {Array<number>} parameters - Array of current parameter values
   * @param {function} parameterizedFunction - The parameters and returns a function with the independent variable as a parameter
   * @param {Array} weightSquare - Square of weights
   * @return {number}
   */
  function errorCalculation(data, parameters, parameterizedFunction, weightSquare) {
    let error = 0;
    const func = parameterizedFunction(parameters);

    for (let i = 0; i < data.x.length; i++) {
      error += Math.pow(data.y[i] - func(data.x[i]), 2) / weightSquare[i];
    }

    return error;
  }

  function rescale$1(input) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    if (!isAnyArray$7(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$7(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$8(input);
    var currentMax = max$7(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;
  }

  const indent$1 = ' '.repeat(2);
  const indentData$1 = ' '.repeat(4);
  function inspectMatrix$1() {
    return inspectMatrixWithOptions$1(this);
  }
  function inspectMatrixWithOptions$1(matrix, options = {}) {
    const {
      maxRows = 15,
      maxColumns = 10,
      maxNumSize = 8
    } = options;
    return `${matrix.constructor.name} {
${indent$1}[
${indentData$1}${inspectData$1(matrix, maxRows, maxColumns, maxNumSize)}
${indent$1}]
${indent$1}rows: ${matrix.rows}
${indent$1}columns: ${matrix.columns}
}`;
  }

  function inspectData$1(matrix, maxRows, maxColumns, maxNumSize) {
    const {
      rows,
      columns
    } = matrix;
    const maxI = Math.min(rows, maxRows);
    const maxJ = Math.min(columns, maxColumns);
    const result = [];

    for (let i = 0; i < maxI; i++) {
      let line = [];

      for (let j = 0; j < maxJ; j++) {
        line.push(formatNumber$1(matrix.get(i, j), maxNumSize));
      }

      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$1}`);
  }

  function formatNumber$1(num, maxNumSize) {
    const numStr = String(num);

    if (numStr.length <= maxNumSize) {
      return numStr.padEnd(maxNumSize, ' ');
    }

    const precise = num.toPrecision(maxNumSize - 2);

    if (precise.length <= maxNumSize) {
      return precise;
    }

    const exponential = num.toExponential(maxNumSize - 2);
    const eIndex = exponential.indexOf('e');
    const e = exponential.slice(eIndex);
    return exponential.slice(0, maxNumSize - e.length) + e;
  }

  function installMathOperations$1(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, Math.pow(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, Math.pow(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$1(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$1(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$1(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$1(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 checkIndices$1(matrix, rowIndices, columnIndices) {
    return {
      row: checkRowIndices$1(matrix, rowIndices),
      column: checkColumnIndices$1(matrix, columnIndices)
    };
  }
  function checkRowIndices$1(matrix, rowIndices) {
    if (typeof rowIndices !== 'object') {
      throw new TypeError('unexpected type for row indices');
    }

    let rowOut = rowIndices.some(r => {
      return r < 0 || r >= matrix.rows;
    });

    if (rowOut) {
      throw new RangeError('row indices are out of range');
    }

    if (!Array.isArray(rowIndices)) rowIndices = Array.from(rowIndices);
    return rowIndices;
  }
  function checkColumnIndices$1(matrix, columnIndices) {
    if (typeof columnIndices !== 'object') {
      throw new TypeError('unexpected type for column indices');
    }

    let columnOut = columnIndices.some(c => {
      return c < 0 || c >= matrix.columns;
    });

    if (columnOut) {
      throw new RangeError('column indices are out of range');
    }

    if (!Array.isArray(columnIndices)) columnIndices = Array.from(columnIndices);
    return columnIndices;
  }
  function checkRange$1(matrix, startRow, endRow, startColumn, endColumn) {
    if (arguments.length !== 5) {
      throw new RangeError('expected 4 arguments');
    }

    checkNumber$1('startRow', startRow);
    checkNumber$1('endRow', endRow);
    checkNumber$1('startColumn', startColumn);
    checkNumber$1('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$1(length, value = 0) {
    let array = [];

    for (let i = 0; i < length; i++) {
      array.push(value);
    }

    return array;
  }

  function checkNumber$1(name, value) {
    if (typeof value !== 'number') {
      throw new TypeError(`${name} must be a number`);
    }
  }

  function checkNonEmpty$1(matrix) {
    if (matrix.isEmpty()) {
      throw new Error('Empty matrix has no elements to index');
    }
  }

  function sumByRow$1(matrix) {
    let sum = newArray$1(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$1(matrix) {
    let sum = newArray$1(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$1(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$1(matrix) {
    let sum = newArray$1(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$1(matrix) {
    let sum = newArray$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(matrix) {
    const scale = [];

    for (let i = 0; i < matrix.rows; i++) {
      let sum = 0;

      for (let j = 0; j < matrix.columns; j++) {
        sum += Math.pow(matrix.get(i, j), 2) / (matrix.columns - 1);
      }

      scale.push(Math.sqrt(sum));
    }

    return scale;
  }
  function scaleByRow$1(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$1(matrix) {
    const scale = [];

    for (let j = 0; j < matrix.columns; j++) {
      let sum = 0;

      for (let i = 0; i < matrix.rows; i++) {
        sum += Math.pow(matrix.get(i, j), 2) / (matrix.rows - 1);
      }

      scale.push(Math.sqrt(sum));
    }

    return scale;
  }
  function scaleByColumn$1(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$1(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 += Math.pow(matrix.get(i, j), 2) / divider;
      }
    }

    return Math.sqrt(sum);
  }
  function scaleAll$1(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$1 {
    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$2(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$2(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$2(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$2(rows, columns);
    }

    static ones(rows, columns) {
      return new Matrix$2(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$2(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$2(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$2(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$1.isMatrix(value) ? value : new Matrix$2(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;
    }

    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$2(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$1(this, index);
      let row = [];

      for (let i = 0; i < this.columns; i++) {
        row.push(this.get(index, i));
      }

      return row;
    }

    getRowVector(index) {
      return Matrix$2.rowVector(this.getRow(index));
    }

    setRow(index, array) {
      checkRowIndex$1(this, index);
      array = checkRowVector$1(this, array);

      for (let i = 0; i < this.columns; i++) {
        this.set(index, i, array[i]);
      }

      return this;
    }

    swapRows(row1, row2) {
      checkRowIndex$1(this, row1);
      checkRowIndex$1(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$1(this, index);
      let column = [];

      for (let i = 0; i < this.rows; i++) {
        column.push(this.get(i, index));
      }

      return column;
    }

    getColumnVector(index) {
      return Matrix$2.columnVector(this.getColumn(index));
    }

    setColumn(index, array) {
      checkColumnIndex$1(this, index);
      array = checkColumnVector$1(this, array);

      for (let i = 0; i < this.rows; i++) {
        this.set(i, index, array[i]);
      }

      return this;
    }

    swapColumns(column1, column2) {
      checkColumnIndex$1(this, column1);
      checkColumnIndex$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(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$1(this, index);

      for (let i = 0; i < this.rows; i++) {
        this.set(i, index, this.get(i, index) * value);
      }

      return this;
    }

    max() {
      if (this.isEmpty()) {
        return NaN;
      }

      let v = this.get(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);
          }
        }
      }

      return v;
    }

    maxIndex() {
      checkNonEmpty$1(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() {
      if (this.isEmpty()) {
        return NaN;
      }

      let v = this.get(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);
          }
        }
      }

      return v;
    }

    minIndex() {
      checkNonEmpty$1(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$1(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$1(this, row);
      checkNonEmpty$1(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$1(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$1(this, row);
      checkNonEmpty$1(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$1(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$1(this, column);
      checkNonEmpty$1(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$1(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$1(this, column);
      checkNonEmpty$1(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') {
      let result = 0;

      if (type === 'max') {
        return this.max();
      } else if (type === 'frobenius') {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            result = result + this.get(i, j) * this.get(i, j);
          }
        }

        return Math.sqrt(result);
      } else {
        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$1.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$2.checkMatrix(other);
      let m = this.rows;
      let n = this.columns;
      let p = other.columns;
      let result = new Matrix$2(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;
    }

    strassen2x2(other) {
      other = Matrix$2.checkMatrix(other);
      let result = new Matrix$2(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$2.checkMatrix(other);
      let result = new Matrix$2(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$2.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$1.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$1.add(a11, a22), AbstractMatrix$1.add(b11, b22), halfRows, halfCols);
        let m2 = blockMult(AbstractMatrix$1.add(a21, a22), b11, halfRows, halfCols);
        let m3 = blockMult(a11, AbstractMatrix$1.sub(b12, b22), halfRows, halfCols);
        let m4 = blockMult(a22, AbstractMatrix$1.sub(b21, b11), halfRows, halfCols);
        let m5 = blockMult(AbstractMatrix$1.add(a11, a12), b22, halfRows, halfCols);
        let m6 = blockMult(AbstractMatrix$1.sub(a21, a11), AbstractMatrix$1.add(b11, b12), halfRows, halfCols);
        let m7 = blockMult(AbstractMatrix$1.sub(a12, a22), AbstractMatrix$1.add(b21, b22), halfRows, halfCols); // Combine intermediate values into the output.

        let c11 = AbstractMatrix$1.add(m1, m4);
        c11.sub(m5);
        c11.add(m7);
        let c12 = AbstractMatrix$1.add(m3, m5);
        let c21 = AbstractMatrix$1.add(m2, m4);
        let c22 = AbstractMatrix$1.sub(m1, m2);
        c22.add(m3);
        c22.add(m6); // Crop output to the desired size (undo dynamic padding).

        let resultat = AbstractMatrix$1.zeros(2 * c11.rows, 2 * c11.columns);
        resultat = resultat.setSubMatrix(c11, 0, 0);
        resultat = resultat.setSubMatrix(c12, c11.rows, 0);
        resultat = resultat.setSubMatrix(c21, 0, c11.columns);
        resultat = resultat.setSubMatrix(c22, c11.rows, c11.columns);
        return resultat.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$2(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$2(this.rows, this.columns);

      for (let i = 0; i < this.columns; i++) {
        const column = this.getColumn(i);

        if (column.length) {
          rescale$1(column, {
            min: min,
            max: 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$2.checkMatrix(other);
      let m = this.rows;
      let n = this.columns;
      let p = other.rows;
      let q = other.columns;
      let result = new Matrix$2(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$2.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$2.eye(n, n));
      let IxB = Matrix$2.eye(m, m).kroneckerProduct(other);
      return AxI.add(IxB);
    }

    transpose() {
      let result = new Matrix$2(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$1) {
      for (let i = 0; i < this.rows; i++) {
        this.setRow(i, this.getRow(i).sort(compareFunction));
      }

      return this;
    }

    sortColumns(compareFunction = compareNumbers$1) {
      for (let i = 0; i < this.columns; i++) {
        this.setColumn(i, this.getColumn(i).sort(compareFunction));
      }

      return this;
    }

    subMatrix(startRow, endRow, startColumn, endColumn) {
      checkRange$1(this, startRow, endRow, startColumn, endColumn);
      let newMatrix = new Matrix$2(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$2(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$2(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$2.checkMatrix(matrix);

      if (matrix.isEmpty()) {
        return this;
      }

      let endRow = startRow + matrix.rows - 1;
      let endColumn = startColumn + matrix.columns - 1;
      checkRange$1(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) {
      let indices = checkIndices$1(this, rowIndices, columnIndices);
      let newMatrix = new Matrix$2(rowIndices.length, columnIndices.length);

      for (let i = 0; i < indices.row.length; i++) {
        let rowIndex = indices.row[i];

        for (let j = 0; j < indices.column.length; j++) {
          let columnIndex = indices.column[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() {
      let newMatrix = new Matrix$2(this.rows, this.columns);

      for (let row = 0; row < this.rows; row++) {
        for (let column = 0; column < this.columns; column++) {
          newMatrix.set(row, column, this.get(row, column));
        }
      }

      return newMatrix;
    }

    sum(by) {
      switch (by) {
        case 'row':
          return sumByRow$1(this);

        case 'column':
          return sumByColumn$1(this);

        case undefined:
          return sumAll$1(this);

        default:
          throw new Error(`invalid option: ${by}`);
      }
    }

    product(by) {
      switch (by) {
        case 'row':
          return productByRow$1(this);

        case 'column':
          return productByColumn$1(this);

        case undefined:
          return productAll$1(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 (!Array.isArray(mean)) {
              throw new TypeError('mean must be an array');
            }

            return varianceByRow$1(this, unbiased, mean);
          }

        case 'column':
          {
            if (!Array.isArray(mean)) {
              throw new TypeError('mean must be an array');
            }

            return varianceByColumn$1(this, unbiased, mean);
          }

        case undefined:
          {
            if (typeof mean !== 'number') {
              throw new TypeError('mean must be a number');
            }

            return varianceAll$1(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 (!Array.isArray(center)) {
              throw new TypeError('center must be an array');
            }

            centerByRow$1(this, center);
            return this;
          }

        case 'column':
          {
            if (!Array.isArray(center)) {
              throw new TypeError('center must be an array');
            }

            centerByColumn$1(this, center);
            return this;
          }

        case undefined:
          {
            if (typeof center !== 'number') {
              throw new TypeError('center must be a number');
            }

            centerAll$1(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$1(this);
            } else if (!Array.isArray(scale)) {
              throw new TypeError('scale must be an array');
            }

            scaleByRow$1(this, scale);
            return this;
          }

        case 'column':
          {
            if (scale === undefined) {
              scale = getScaleByColumn$1(this);
            } else if (!Array.isArray(scale)) {
              throw new TypeError('scale must be an array');
            }

            scaleByColumn$1(this, scale);
            return this;
          }

        case undefined:
          {
            if (scale === undefined) {
              scale = getScaleAll$1(this);
            } else if (typeof scale !== 'number') {
              throw new TypeError('scale must be a number');
            }

            scaleAll$1(this, scale);
            return this;
          }

        default:
          throw new Error(`invalid option: ${by}`);
      }
    }

    toString(options) {
      return inspectMatrixWithOptions$1(this, options);
    }

  }
  AbstractMatrix$1.prototype.klass = 'Matrix';

  if (typeof Symbol !== 'undefined') {
    AbstractMatrix$1.prototype[Symbol.for('nodejs.util.inspect.custom')] = inspectMatrix$1;
  }

  function compareNumbers$1(a, b) {
    return a - b;
  } // Synonyms


  AbstractMatrix$1.random = AbstractMatrix$1.rand;
  AbstractMatrix$1.randomInt = AbstractMatrix$1.randInt;
  AbstractMatrix$1.diagonal = AbstractMatrix$1.diag;
  AbstractMatrix$1.prototype.diagonal = AbstractMatrix$1.prototype.diag;
  AbstractMatrix$1.identity = AbstractMatrix$1.eye;
  AbstractMatrix$1.prototype.negate = AbstractMatrix$1.prototype.neg;
  AbstractMatrix$1.prototype.tensorProduct = AbstractMatrix$1.prototype.kroneckerProduct;
  class Matrix$2 extends AbstractMatrix$1 {
    constructor(nRows, nColumns) {
      super();

      if (Matrix$2.isMatrix(nRows)) {
        // eslint-disable-next-line no-constructor-return
        return nRows.clone();
      } else if (Number.isInteger(nRows) && nRows >= 0) {
        // Create an empty matrix
        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');
        }
      } else if (Array.isArray(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');
          }

          this.data.push(Float64Array.from(arrayData[i]));
        }
      } else {
        throw new TypeError('First argument must be a positive number or an array');
      }

      this.rows = nRows;
      this.columns = nColumns;
    }

    set(rowIndex, columnIndex, value) {
      this.data[rowIndex][columnIndex] = value;
      return this;
    }

    get(rowIndex, columnIndex) {
      return this.data[rowIndex][columnIndex];
    }

    removeRow(index) {
      checkRowIndex$1(this, index);
      this.data.splice(index, 1);
      this.rows -= 1;
      return this;
    }

    addRow(index, array) {
      if (array === undefined) {
        array = index;
        index = this.rows;
      }

      checkRowIndex$1(this, index, true);
      array = Float64Array.from(checkRowVector$1(this, array));
      this.data.splice(index, 0, array);
      this.rows += 1;
      return this;
    }

    removeColumn(index) {
      checkColumnIndex$1(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$1(this, index, true);
      array = checkColumnVector$1(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$1(AbstractMatrix$1, Matrix$2);

  class WrapperMatrix2D extends AbstractMatrix$1 {
    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];
    }

  }

  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$2.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$2(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$2(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$2.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$2(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$2(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$2(m, nu);
      let V = new Matrix$2(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$2.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$2.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$2.diag(value));
    }

    inverse() {
      let V = this.V;
      let e = this.threshold;
      let vrows = V.rows;
      let vcols = V.columns;
      let X = new Matrix$2(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$2(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$2.diag(this.s);
    }

  }

  function inverse(matrix, useSVD = false) {
    matrix = WrapperMatrix2D.checkMatrix(matrix);

    if (useSVD) {
      return new SingularValueDecomposition(matrix).inverse();
    } else {
      return solve(matrix, Matrix$2.eye(matrix.rows));
    }
  }
  function solve(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);
    }
  }

  /**
   * Difference of the matrix function over the parameters
   * @ignore
   * @param {{x:Array<number>, y:Array<number>}} data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ]
   * @param {Array<number>} evaluatedData - Array of previous evaluated function values
   * @param {Array<number>} params - Array of previous parameter values
   * @param {number|array} gradientDifference - The step size to approximate the jacobian matrix
   * @param {boolean} centralDifference - If true the jacobian matrix is approximated by central differences otherwise by forward differences
   * @param {function} paramFunction - The parameters and returns a function with the independent variable as a parameter
   * @return {Matrix}
   */

  function gradientFunction(data, evaluatedData, params, gradientDifference, paramFunction, centralDifference) {
    const nbParams = params.length;
    const nbPoints = data.x.length;
    let ans = Matrix$2.zeros(nbParams, nbPoints);
    let rowIndex = 0;

    for (let param = 0; param < nbParams; param++) {
      if (gradientDifference[param] === 0) continue;
      let delta = gradientDifference[param];
      let auxParams = params.slice();
      auxParams[param] += delta;
      let funcParam = paramFunction(auxParams);

      if (!centralDifference) {
        for (let point = 0; point < nbPoints; point++) {
          ans.set(rowIndex, point, (evaluatedData[point] - funcParam(data.x[point])) / delta);
        }
      } else {
        auxParams = params.slice();
        auxParams[param] -= delta;
        delta *= 2;
        let funcParam2 = paramFunction(auxParams);

        for (let point = 0; point < nbPoints; point++) {
          ans.set(rowIndex, point, (funcParam2(data.x[point]) - funcParam(data.x[point])) / delta);
        }
      }

      rowIndex++;
    }

    return ans;
  }

  /**
   * Matrix function over the samples
   * @ignore
   * @param {{x:Array<number>, y:Array<number>}} data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ]
   * @param {Array<number>} evaluatedData - Array of previous evaluated function values
   * @return {Matrix}
   */

  function matrixFunction(data, evaluatedData) {
    const m = data.x.length;
    let ans = new Matrix$2(m, 1);

    for (let point = 0; point < m; point++) {
      ans.set(point, 0, data.y[point] - evaluatedData[point]);
    }

    return ans;
  }
  /**
   * Iteration for Levenberg-Marquardt
   * @ignore
   * @param {{x:Array<number>, y:Array<number>}} data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ]
   * @param {Array<number>} params - Array of previous parameter values
   * @param {number} damping - Levenberg-Marquardt parameter
   * @param {number|array} gradientDifference - The step size to approximate the jacobian matrix
   * @param {boolean} centralDifference - If true the jacobian matrix is approximated by central differences otherwise by forward differences
   * @param {function} parameterizedFunction - The parameters and returns a function with the independent variable as a parameter
   * @return {Array<number>}
   */


  function step(data, params, damping, gradientDifference, parameterizedFunction, centralDifference, weights) {
    let value = damping;
    let identity = Matrix$2.eye(params.length, params.length, value);
    const func = parameterizedFunction(params);
    let evaluatedData = new Float64Array(data.x.length);

    for (let i = 0; i < data.x.length; i++) {
      evaluatedData[i] = func(data.x[i]);
    }

    let gradientFunc = gradientFunction(data, evaluatedData, params, gradientDifference, parameterizedFunction, centralDifference);
    let residualError = matrixFunction(data, evaluatedData);
    let inverseMatrix = inverse(identity.add(gradientFunc.mmul(gradientFunc.transpose().scale('row', {
      scale: weights
    }))));
    let jacobianWeigthResidualError = gradientFunc.mmul(residualError.scale('row', {
      scale: weights
    }));
    let perturbations = inverseMatrix.mmul(jacobianWeigthResidualError);
    return {
      perturbations,
      jacobianWeigthResidualError
    };
  }

  /**
   * Curve fitting algorithm
   * @param {{x:Array<number>, y:Array<number>}} data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ]
   * @param {function} parameterizedFunction - The parameters and returns a function with the independent variable as a parameter
   * @param {object} [options] - Options object
   * @param {number|array} [options.weights = 1] - weighting vector, if the length does not match with the number of data points, the vector is reconstructed with first value.
   * @param {number} [options.damping = 1e-2] - Levenberg-Marquardt parameter, small values of the damping parameter λ result in a Gauss-Newton update and large
  values of λ result in a gradient descent update
   * @param {number} [options.dampingStepDown = 9] - factor to reduce the damping (Levenberg-Marquardt parameter) when there is not an improvement when updating parameters.
   * @param {number} [options.dampingStepUp = 11] - factor to increase the damping (Levenberg-Marquardt parameter) when there is an improvement when updating parameters.
   * @param {number} [options.improvementThreshold = 1e-3] - the threshold to define an improvement through an update of parameters
   * @param {number|array} [options.gradientDifference = 10e-2] - The step size to approximate the jacobian matrix
   * @param {boolean} [options.centralDifference = false] - If true the jacobian matrix is approximated by central differences otherwise by forward differences
   * @param {Array<number>} [options.minValues] - Minimum allowed values for parameters
   * @param {Array<number>} [options.maxValues] - Maximum allowed values for parameters
   * @param {Array<number>} [options.initialValues] - Array of initial parameter values
   * @param {number} [options.maxIterations = 100] - Maximum of allowed iterations
   * @param {number} [options.errorTolerance = 10e-3] - Minimum uncertainty allowed for each point.
   * @param {number} [options.timeout] - maximum time running before throw in seconds.
   * @return {{parameterValues: Array<number>, parameterError: number, iterations: number}}
   */

  function levenbergMarquardt(data, parameterizedFunction, options = {}) {
    let {
      checkTimeout,
      minValues,
      maxValues,
      parameters,
      weightSquare,
      damping,
      dampingStepUp,
      dampingStepDown,
      maxIterations,
      errorTolerance,
      centralDifference,
      gradientDifference,
      improvementThreshold
    } = checkOptions$1(data, parameterizedFunction, options);
    let error = errorCalculation(data, parameters, parameterizedFunction, weightSquare);
    let converged = error <= errorTolerance;
    let iteration = 0;

    for (; iteration < maxIterations && !converged; iteration++) {
      let previousError = error;
      let {
        perturbations,
        jacobianWeigthResidualError
      } = step(data, parameters, damping, gradientDifference, parameterizedFunction, centralDifference, weightSquare);

      for (let k = 0; k < parameters.length; k++) {
        parameters[k] = Math.min(Math.max(minValues[k], parameters[k] - perturbations.get(k, 0)), maxValues[k]);
      }

      error = errorCalculation(data, parameters, parameterizedFunction, weightSquare);
      if (isNaN(error)) break;
      let improvementMetric = (previousError - error) / perturbations.transpose().mmul(perturbations.mulS(damping).add(jacobianWeigthResidualError)).get(0, 0);

      if (improvementMetric > improvementThreshold) {
        damping = Math.max(damping / dampingStepDown, 1e-7);
      } else {
        error = previousError;
        damping = Math.min(damping * dampingStepUp, 1e7);
      }

      if (checkTimeout()) {
        throw new Error(`The execution time is over to ${options.timeout} seconds`);
      }

      converged = error <= errorTolerance;
    }

    return {
      parameterValues: parameters,
      parameterError: error,
      iterations: iteration
    };
  }

  const LEVENBERG_MARQUARDT = 1;
  function selectMethod(optimizationOptions = {}) {
    let {
      kind,
      options
    } = optimizationOptions;
    kind = getKind(kind);

    switch (kind) {
      case LEVENBERG_MARQUARDT:
        return {
          algorithm: levenbergMarquardt,
          optimizationOptions: checkOptions(kind, options)
        };

      default:
        throw new Error(`Unknown kind algorithm`);
    }
  }

  function checkOptions(kind, options = {}) {
    // eslint-disable-next-line default-case
    switch (kind) {
      case LEVENBERG_MARQUARDT:
        return Object.assign({}, lmOptions, options);
    }
  }

  function getKind(kind) {
    if (typeof kind !== 'string') return kind;

    switch (kind.toLowerCase().replace(/[^a-z]/g, '')) {
      case 'lm':
      case 'levenbergmarquardt':
        return LEVENBERG_MARQUARDT;

      default:
        throw new Error(`Unknown kind algorithm`);
    }
  }

  const lmOptions = {
    damping: 1.5,
    maxIterations: 100,
    errorTolerance: 1e-8
  };

  // const STATE_MIN = 1;
  // const STATE_MAX = 2;
  // const STATE_GRADIENT_DIFFERENCE = 3;
  // const X = 0;
  // const Y = 1;
  // const WIDTH = 2;
  // const MU = 3;
  // const keys = ['x', 'y', 'width', 'mu'];

  /**
   * Fits a set of points to the sum of a set of bell functions.
   * @param {object} data - An object containing the x and y data to be fitted.
   * @param {array} peaks - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
   * @param {object} [options = {}]
   * @param {object} [options.shape={}] - it's specify the kind of shape used to fitting.
   * @param {string} [options.shape.kind = 'gaussian'] - kind of shape; lorentzian, gaussian and pseudovoigt are supported.
   * @param {object} [options.optimization = {}] - it's specify the kind and options of the algorithm use to optimize parameters.
   * @param {object} [options.optimization.kind = 'lm'] - kind of algorithm. By default it's levenberg-marquardt.
   * @param {object} [options.optimization.parameters] - options of each parameter to be optimized e.g. For a gaussian shape
   *  it could have x, y and with properties, each of which could contain init, min, max and gradientDifference, those options will define the guess,
   *  the min and max value of the parameter (search space) and the step size to approximate the jacobian matrix respectively. Those options could be a number,
   *  array of numbers, callback, or array of callbacks. Each kind of shape has default parameters so it could be undefined.
   * @param {object} [options.optimization.parameters.x] - options for x parameter.
   * @param {number|callback|array<number|callback>} [options.optimization.parameters.x.init] - definition of the starting point of the parameter (the guess),
   *  if it is a callback the method pass the peak as the unique input, if it is an array the first element define the guess of the first peak and so on.
   * @param {number|callback|array<number|callback>} [options.optimization.parameters.x.min] - definition of the lower limit of the parameter,
   *  if it is a callback the method pass the peak as the unique input, if it is an array the first element define the min of the first peak and so on.
   * @param {number|callback|array<number|callback>} [options.optimization.parameters.x.max] - definition of the upper limit of the parameter,
   *  if it is a callback the method pass the peak as the unique input, if it is an array the first element define the max of the first peak and so on.
   * @param {number|callback|array<number|callback>} [options.optimization.parameters.x.gradientDifference] - definition of  the step size to approximate the jacobian matrix of the parameter,
   *  if it is a callback the method pass the peak as the unique input, if it is an array the first element define the gradientDifference of the first peak and so on.
   * @param {object} [options.optimization.options = {}] - options for the specific kind of algorithm.
   * @param {number} [options.optimization.options.timeout] - maximum time running before break in seconds.
   * @param {number} [options.optimization.options.damping=1.5]
   * @param {number} [options.optimization.options.maxIterations=100]
   * @param {number} [options.optimization.options.errorTolerance=1e-8]
   * @returns {object} - A object with fitting error and the list of optimized parameters { parameters: [ {x, y, width} ], error } if the kind of shape is pseudoVoigt mu parameter is optimized.
   */

  function optimize(data, peakList, options = {}) {
    const {
      y,
      x,
      maxY,
      peaks,
      paramsFunc,
      optimization
    } = checkInput(data, peakList, options);
    let parameters = optimization.parameters;
    let nbShapes = peaks.length;
    let parameterKey = Object.keys(parameters);
    let nbParams = nbShapes * parameterKey.length;
    let pMin = new Float64Array(nbParams);
    let pMax = new Float64Array(nbParams);
    let pInit = new Float64Array(nbParams);
    let gradientDifference = new Float64Array(nbParams);

    for (let i = 0; i < nbShapes; i++) {
      let peak = peaks[i];

      for (let k = 0; k < parameterKey.length; k++) {
        let key = parameterKey[k];
        let init = parameters[key].init;
        let min = parameters[key].min;
        let max = parameters[key].max;
        let gradientDifferenceValue = parameters[key].gradientDifference;
        pInit[i + k * nbShapes] = init[i % init.length](peak);
        pMin[i + k * nbShapes] = min[i % min.length](peak);
        pMax[i + k * nbShapes] = max[i % max.length](peak);
        gradientDifference[i + k * nbShapes] = gradientDifferenceValue[i % gradientDifferenceValue.length](peak);
      }
    }

    let {
      algorithm,
      optimizationOptions
    } = selectMethod(optimization);
    optimizationOptions.minValues = pMin;
    optimizationOptions.maxValues = pMax;
    optimizationOptions.initialValues = pInit;
    optimizationOptions.gradientDifference = gradientDifference;
    let pFit = algorithm({
      x,
      y
    }, paramsFunc, optimizationOptions);
    let {
      parameterError: error,
      iterations
    } = pFit;
    let result = {
      error,
      iterations,
      peaks
    };

    for (let i = 0; i < nbShapes; i++) {
      pFit.parameterValues[i + nbShapes] *= maxY;

      for (let k = 0; k < parameterKey.length; k++) {
        // we modify the optimized parameters
        peaks[i][parameterKey[k]] = pFit.parameterValues[i + k * nbShapes];
      }
    }

    return result;
  }

  /**
   * Returns the closest index of a `target` in an ordered array
   * @param {array<Number>} array
   * @param {number} target
   */
  function xFindClosestIndex$2(array, target) {
    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;
    }
  }

  /**
   * Returns an object with {fromIndex, toIndex} for a specific from / to
   * @param {array} x
   * @param {object} [options={}]
   * @param {number} [options.from] - First value for xyIntegration in the X scale
   * @param {number} [options.fromIndex=0] - First point for xyIntegration
   * @param {number} [options.to] - Last value for xyIntegration in the X scale
   * @param {number} [options.toIndex=x.length-1] - Last point for xyIntegration
   */

  function xGetFromToIndex$1(x, options = {}) {
    let {
      fromIndex,
      toIndex,
      from,
      to
    } = options;

    if (fromIndex === undefined) {
      if (from !== undefined) {
        fromIndex = xFindClosestIndex$2(x, from);
      } else {
        fromIndex = 0;
      }
    }

    if (toIndex === undefined) {
      if (to !== undefined) {
        toIndex = xFindClosestIndex$2(x, to);
      } else {
        toIndex = x.length - 1;
      }
    }

    if (fromIndex > toIndex) [fromIndex, toIndex] = [toIndex, fromIndex];
    return {
      fromIndex,
      toIndex
    };
  }

  /**
   * Group peaks based on factor and add group property in peaks
   * @param {array} peakList
   * @param {number} factor
   */
  function groupPeaks(peakList, factor = 1) {
    if (peakList.length === 0) return [];
    let peaks = peakList.sort((a, b) => a.x - b.x);
    let previousPeak = {
      x: Number.NEGATIVE_INFINITY,
      width: 1
    };
    let currentGroup = [previousPeak];
    let groups = [];

    for (let peak of peaks) {
      if ((peak.x - previousPeak.x) / (peak.width + previousPeak.width) <= factor / 2) {
        currentGroup.push(peak);
      } else {
        currentGroup = [peak];
        groups.push(currentGroup);
      }

      peak.group = groups.length - 1;
      previousPeak = peak;
    }

    return groups;
  }

  /**
   * Optimize the position (x), max intensity (y), full width at half maximum (width)
   * and the ratio of gaussian contribution (mu) if it's required. It supports three kind of shapes: gaussian, lorentzian and pseudovoigt
   * @param {object} data - An object containing the x and y data to be fitted.
   * @param {Array} peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
   * @param {object} [options = {}] -
   * @param {number} [options.factorWidth = 1] - times of width to group peaks.
   * @param {number} [options.factorLimits = 2] - times of width to use to optimize peaks
   * @param {object} [options.shape={}] - it's specify the kind of shape used to fitting.
   * @param {string} [options.shape.kind='gaussian'] - kind of shape; lorentzian, gaussian and pseudovoigt are supported.
   * @param {string} [options.shape.options={}] - options depending the kind of shape
   * @param {object} [options.optimization={}] - it's specify the kind and options of the algorithm use to optimize parameters.
   * @param {string} [options.optimization.kind='lm'] - kind of algorithm. By default it's levenberg-marquardt.
   * @param {object} [options.optimization.options={}] - options for the specific kind of algorithm.
   * @param {number} [options.optimization.options.timeout=10] - maximum time running before break in seconds.
   */

  function optimizePeaks(data, peakList, options = {}) {
    const {
      factorWidth = 1,
      factorLimits = 2,
      shape = {
        kind: 'gaussian'
      },
      optimization = {
        kind: 'lm',
        options: {
          timeout: 10
        }
      }
    } = options;

    if (data.x[0] > data.x[1]) {
      data.x.reverse();
      data.y.reverse();
    }

    let groups = groupPeaks(peakList, factorWidth);
    let results = [];

    for (const peaks of groups) {
      const firstPeak = peaks[0];
      const lastPeak = peaks[peaks.length - 1];
      const from = firstPeak.x - firstPeak.width * factorLimits;
      const to = lastPeak.x + lastPeak.width * factorLimits;
      const {
        fromIndex,
        toIndex
      } = xGetFromToIndex$1(data.x, {
        from,
        to
      }); // Multiple peaks

      const currentRange = {
        x: data.x.slice(fromIndex, toIndex),
        y: data.y.slice(fromIndex, toIndex)
      };

      if (currentRange.x.length > 5) {
        let {
          peaks: optimizedPeaks
        } = optimize(currentRange, peaks, {
          shape,
          optimization
        });
        results = results.concat(optimizedPeaks);
      } else {
        results = results.concat(peaks);
      }
    }

    return results;
  }

  /**
   * This function try to join the peaks that seems to belong to a broad signal in a single broad peak.
   * @param {Array} peakList - A list of initial parameters to be optimized. e.g. coming from a peak picking [{x, y, width}].
   * @param {object} [options = {}] - options
   * @param {number} [options.width=0.25] - width limit to join peaks.
   * @param {object} [options.shape={}] - it's specify the kind of shape used to fitting.
   * @param {string} [options.shape.kind = 'gaussian'] - kind of shape; lorentzian, gaussian and pseudovoigt are supported.
   * @param {object} [options.optimization = {}] - it's specify the kind and options of the algorithm use to optimize parameters.
   * @param {string} [options.optimization.kind = 'lm'] - kind of algorithm. By default it's levenberg-marquardt.
   * @param {number} [options.optimization.options.timeout = 10] - maximum time running before break in seconds.
   * @param {object} [options.optimization.options = {}] - options for the specific kind of algorithm.
   */

  function joinBroadPeaks(peakList, options = {}) {
    let {
      width = 0.25,
      shape = {
        kind: 'gaussian'
      },
      optimization = {
        kind: 'lm',
        timeout: 10
      }
    } = options;
    let broadLines = []; // Optimize the possible broad lines

    let max = 0;
    let maxI = 0;
    let count = 1;

    for (let i = peakList.length - 1; i >= 0; i--) {
      if (peakList[i].soft) {
        broadLines.push(peakList.splice(i, 1)[0]);
      }
    } // Push a feke peak


    broadLines.push({
      x: Number.MAX_VALUE
    });
    let candidates = {
      x: [broadLines[0].x],
      y: [broadLines[0].y]
    };
    let indexes = [0];

    for (let i = 1; i < broadLines.length; i++) {
      if (Math.abs(broadLines[i - 1].x - broadLines[i].x) < width) {
        candidates.x.push(broadLines[i].x);
        candidates.y.push(broadLines[i].y);

        if (broadLines[i].y > max) {
          max = broadLines[i].y;
          maxI = i;
        }

        indexes.push(i);
        count++;
      } else {
        if (count > 2) {
          let fitted = optimize(candidates, [{
            x: broadLines[maxI].x,
            y: max,
            width: Math.abs(candidates.x[0] - candidates.x[candidates.x.length - 1])
          }], {
            shape,
            optimization
          });
          let {
            peaks: peak
          } = fitted;
          peak[0].index = Math.floor(indexes.reduce((a, b) => a + b, 0) / indexes.length);
          peak[0].soft = false;
          peakList.push(peak[0]);
        } else {
          // Put back the candidates to the signals list
          indexes.forEach(index => {
            peakList.push(broadLines[index]);
          });
        }

        candidates = {
          x: [broadLines[i].x],
          y: [broadLines[i].y]
        };
        indexes = [i];
        max = broadLines[i].y;
        maxI = i;
        count = 1;
      }
    }

    peakList.sort(function (a, b) {
      return a.x - b.x;
    });
    return peakList;
  }

  /**
   * This method will allow to enlarge peaks and prevent overlap between peaks
   * Because peaks may not be symmetric after we add 2 properties, from and to.
   * @param {Array} peakList
   * @param {object} [options={}]
   * @param {number} [options.factor=2]
   * @param {boolean} [options.overlap=false] by default we don't allow overlap
   * @return {Array} peakList
   */
  function broadenPeaks(peakList, options = {}) {
    const {
      factor = 2,
      overlap = false
    } = options;

    for (let peak of peakList) {
      if (!peak.right || !peak.left) {
        peak.from = peak.x - peak.width / 2 * factor;
        peak.to = peak.x + peak.width / 2 * factor;
      } else {
        peak.from = peak.x - (peak.x - peak.left.x) * factor;
        peak.to = peak.x + (peak.right.x - peak.x) * factor;
      }
    }

    if (!overlap) {
      for (let i = 0; i < peakList.length - 1; i++) {
        let peak = peakList[i];
        let nextPeak = peakList[i + 1];

        if (peak.to > nextPeak.from) {
          peak.to = nextPeak.from = (peak.to + nextPeak.from) / 2;
        }
      }
    }

    for (let peak of peakList) {
      peak.width = peak.to - peak.from;
    }

    return peakList;
  }

  var src$p = /*#__PURE__*/Object.freeze({
    __proto__: null,
    gsd: gsd$2,
    optimizePeaks: optimizePeaks,
    joinBroadPeaks: joinBroadPeaks,
    broadenPeaks: broadenPeaks
  });

  /**
   * Parse a text-file and convert it to an array of XY points
   * @param {string} text - csv or tsv strings
   * @param {object} [options={}]
   * @param {boolean} [options.rescale = false] - will set the maximum value to 1
   * @param {boolean} [options.uniqueX = false] - Make the X values unique (works only with 'xxyy' format). If the X value is repeated the sum of Y is done.
   * @param {number} [options.xColumn = 0] - A number that specifies the x column
   * @param {number} [options.yColumn = 1] - A number that specifies the y column
   * @param {boolean} [options.bestGuess=false] Will try to guess which columns are the best
   * @param {number} [options.numberColumns=Number.MAX_SAFE_INTEGER] If the file has 10 columns and you specify here 2 it will reflow the file
   * @param {number} [options.maxNumberColumns = (Math.max(xColumn, yColumn)+1)] - A number that specifies the maximum number of y columns
   * @param {number} [options.minNumberColumns = (Math.min(xColumn, yColumn)+1)] - A number that specifies the minimum number of y columns
   * @param {boolean} [options.keepInfo = false] - shoud we keep the non numeric lines. In this case the system will return an object {data, info}
   * @return {object{x:<Array<number>>,y:<Array<number>>}
   */

  function parseXY$1(text, options = {}) {
    let {
      rescale = false,
      uniqueX: uniqueX$1 = false,
      xColumn = 0,
      yColumn = 1,
      keepInfo = false,
      bestGuess = false,
      numberColumns = Number.MAX_SAFE_INTEGER,
      maxNumberColumns = Number.MAX_SAFE_INTEGER,
      minNumberColumns = 2
    } = options;
    maxNumberColumns = Math.max(maxNumberColumns, xColumn + 1, yColumn + 1);
    minNumberColumns = Math.max(xColumn + 1, yColumn + 1, minNumberColumns);
    let lines = text.split(/[\r\n]+/);
    let matrix = [];
    let info = [];
    let position = 0;

    for (let l = 0; l < lines.length; l++) {
      let line = lines[l].trim(); // we will consider only lines that contains only numbers

      if (line.match(/[0-9]+/) && line.match(/^[0-9eE,;. \t+-]+$/)) {
        let fields = line.split(/,[; \t]+|[; \t]+/);

        if (fields.length === 1) {
          fields = line.split(/[,; \t]+/);
        }

        if (fields && fields.length >= minNumberColumns && // we filter lines that have not enough or too many columns
        fields.length <= maxNumberColumns) {
          matrix.push(fields.map(value => parseFloat(value.replace(',', '.'))));
          position++;
        }
      } else if (line) {
        info.push({
          position,
          value: line
        });
      }
    }

    if (bestGuess) {
      if (matrix[0] && matrix[0].length === 3 && options.xColumn === undefined && options.yColumn === undefined) {
        // is the first column a seuqnetial number ?
        let skipFirstColumn = true;

        for (let i = 0; i < matrix.length - 1; i++) {
          if (Math.abs(matrix[i][0] - matrix[i + 1][0]) !== 1) {
            skipFirstColumn = false;
          }
        }

        if (skipFirstColumn) {
          xColumn = 1;
          yColumn = 2;
        }
      }

      if (matrix[0] && matrix[0].length > 3) {
        let xs = [];

        for (let row of matrix) {
          for (let i = xColumn; i < row.length; i += 2) {
            xs.push(row[i]);
          }
        }

        if (xIsMonotone$1(xs)) {
          numberColumns = 2;
        }
      }
    }

    if (numberColumns) {
      const newMatrix = [];

      for (const row of matrix) {
        for (let i = 0; i < row.length; i += numberColumns) {
          newMatrix.push(row.slice(i, i + numberColumns));
        }
      }

      matrix = newMatrix;
    }

    const result = {
      x: matrix.map(row => row[xColumn]),
      y: matrix.map(row => row[yColumn])
    };

    if (uniqueX$1) {
      uniqueX(result);
    }

    if (rescale) {
      let maxY = max$7(result.y);

      for (let i = 0; i < result.y.length; i++) {
        result.y[i] /= maxY;
      }
    }

    if (!keepInfo) return result;
    return {
      info,
      data: result
    };
  }

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

  /**
   * Filter the array by taking the higher peaks and only
   * keep one per slot.
   * There are 2 different slots, the smallest one will have the
   * extra annotation `close` to true
   * @param {array} peaks - array of all the peaks
   * @param {object} [options={}]
   * @param {number} [options.from] - min X value of the window to consider
   * @param {number} [options.to] - max X value of the window to consider
   * @param {number} [options.searchMonoisotopicRatio=0] - search previous peaks with at least ratio height
   * @param {number} [options.limit=20] - max number of peaks
   * @param {number} [options.threshold=0.01] - minimal intensity compare to base peak
   * @param {number} [options.numberSlots=10] - define the number of slots and indirectly the slot width
   * @param {number} [options.numberCloseSlots=50]
   * @returns {array} - copy of peaks with 'close' annotation
   */

  function getBestPeaks$1(peaks, options = {}) {
    const {
      searchMonoisotopicRatio = 0,
      from = peaks.reduce((previous, peak) => Math.min(peak.x, previous), Number.MAX_SAFE_INTEGER),
      to = peaks.reduce((previous, peak) => Math.max(peak.x, previous), Number.MIN_SAFE_INTEGER),
      limit = 20,
      threshold = 0.01,
      numberCloseSlots = 50,
      numberSlots = 10
    } = options;
    let slot = (to - from) / numberSlots;
    let closeSlot = (to - from) / numberCloseSlots;
    let selected = peaks.filter(peak => peak.x >= from && peak.x <= to).map(peak => {
      return {
        peak,
        monoisotopic: false
      };
    });

    if (searchMonoisotopicRatio) {
      selected = selected.sort((a, b) => b.peak.x - a.peak.x);

      for (let i = 0; i < selected.length; i++) {
        let item = selected[i];

        for (let j = i + 1; j < selected.length; j++) {
          let nextItem = selected[j];
          if (item.peak.x - nextItem.peak.x < 0.09) continue;
          if (item.peak.x - nextItem.peak.x > 1.1) break;

          if (nextItem.peak.y > item.peak.y * searchMonoisotopicRatio) {
            item.monoisotopic = false;
            nextItem.monoisotopic = true;
            break;
          }
        }
      }
    }

    selected = selected.sort((a, b) => {
      if (a.monoisotopic && !b.monoisotopic) return -1;
      if (b.monoisotopic && !a.monoisotopic) return 1;
      return b.peak.y - a.peak.y;
    });
    let toReturn = [];
    if (selected.length === 0) return [];
    let minY = selected[0].peak.y * threshold;

    peakLoop: for (let item of selected) {
      if (item.peak.y < minY) {
        if (item.monoisotopic) {
          continue;
        } else {
          break;
        }
      }

      let close = false;

      for (let existing of toReturn) {
        if (Math.abs(existing.x - item.peak.x) < closeSlot) {
          continue peakLoop;
        }

        if (Math.abs(existing.x - item.peak.x) < slot) {
          close = true;
        }
      }

      let newPeak = JSON.parse(JSON.stringify(item.peak));
      newPeak.close = close;
      toReturn.push(newPeak);
      if (toReturn.length === limit) break;
    }

    return toReturn.sort((a, b) => a.x - b.x);
  }

  var getBestPeaks_1 = getBestPeaks$1;

  var array$4 = createCommonjsModule$1(function (module, exports) {

    function compareNumbers(a, b) {
      return a - b;
    }
    /**
     * Computes the sum of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.sum = function sum(values) {
      var sum = 0;

      for (var i = 0; i < values.length; i++) {
        sum += values[i];
      }

      return sum;
    };
    /**
     * Computes the maximum of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.max = function max(values) {
      var max = values[0];
      var l = values.length;

      for (var i = 1; i < l; i++) {
        if (values[i] > max) max = values[i];
      }

      return max;
    };
    /**
     * Computes the minimum of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.min = function min(values) {
      var min = values[0];
      var l = values.length;

      for (var i = 1; i < l; i++) {
        if (values[i] < min) min = values[i];
      }

      return min;
    };
    /**
     * Computes the min and max of the given values
     * @param {Array} values
     * @returns {{min: number, max: number}}
     */


    exports.minMax = function minMax(values) {
      var min = values[0];
      var max = values[0];
      var l = values.length;

      for (var i = 1; i < l; i++) {
        if (values[i] < min) min = values[i];
        if (values[i] > max) max = values[i];
      }

      return {
        min: min,
        max: max
      };
    };
    /**
     * Computes the arithmetic mean of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.arithmeticMean = function arithmeticMean(values) {
      var sum = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        sum += values[i];
      }

      return sum / l;
    };
    /**
     * {@link arithmeticMean}
     */


    exports.mean = exports.arithmeticMean;
    /**
     * Computes the geometric mean of the given values
     * @param {Array} values
     * @returns {number}
     */

    exports.geometricMean = function geometricMean(values) {
      var mul = 1;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        mul *= values[i];
      }

      return Math.pow(mul, 1 / l);
    };
    /**
     * Computes the mean of the log of the given values
     * If the return value is exponentiated, it gives the same result as the
     * geometric mean.
     * @param {Array} values
     * @returns {number}
     */


    exports.logMean = function logMean(values) {
      var lnsum = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        lnsum += Math.log(values[i]);
      }

      return lnsum / l;
    };
    /**
     * Computes the weighted grand mean for a list of means and sample sizes
     * @param {Array} means - Mean values for each set of samples
     * @param {Array} samples - Number of original values for each set of samples
     * @returns {number}
     */


    exports.grandMean = function grandMean(means, samples) {
      var sum = 0;
      var n = 0;
      var l = means.length;

      for (var i = 0; i < l; i++) {
        sum += samples[i] * means[i];
        n += samples[i];
      }

      return sum / n;
    };
    /**
     * Computes the truncated mean of the given values using a given percentage
     * @param {Array} values
     * @param {number} percent - The percentage of values to keep (range: [0,1])
     * @param {boolean} [alreadySorted=false]
     * @returns {number}
     */


    exports.truncatedMean = function truncatedMean(values, percent, alreadySorted) {
      if (alreadySorted === undefined) alreadySorted = false;

      if (!alreadySorted) {
        values = [].concat(values).sort(compareNumbers);
      }

      var l = values.length;
      var k = Math.floor(l * percent);
      var sum = 0;

      for (var i = k; i < l - k; i++) {
        sum += values[i];
      }

      return sum / (l - 2 * k);
    };
    /**
     * Computes the harmonic mean of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.harmonicMean = function harmonicMean(values) {
      var sum = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        if (values[i] === 0) {
          throw new RangeError('value at index ' + i + 'is zero');
        }

        sum += 1 / values[i];
      }

      return l / sum;
    };
    /**
     * Computes the contraharmonic mean of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.contraHarmonicMean = function contraHarmonicMean(values) {
      var r1 = 0;
      var r2 = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        r1 += values[i] * values[i];
        r2 += values[i];
      }

      if (r2 < 0) {
        throw new RangeError('sum of values is negative');
      }

      return r1 / r2;
    };
    /**
     * Computes the median of the given values
     * @param {Array} values
     * @param {boolean} [alreadySorted=false]
     * @returns {number}
     */


    exports.median = function median(values, alreadySorted) {
      if (alreadySorted === undefined) alreadySorted = false;

      if (!alreadySorted) {
        values = [].concat(values).sort(compareNumbers);
      }

      var l = values.length;
      var half = Math.floor(l / 2);

      if (l % 2 === 0) {
        return (values[half - 1] + values[half]) * 0.5;
      } else {
        return values[half];
      }
    };
    /**
     * Computes the variance of the given values
     * @param {Array} values
     * @param {boolean} [unbiased=true] - if true, divide by (n-1); if false, divide by n.
     * @returns {number}
     */


    exports.variance = function variance(values, unbiased) {
      if (unbiased === undefined) unbiased = true;
      var theMean = exports.mean(values);
      var theVariance = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        var x = values[i] - theMean;
        theVariance += x * x;
      }

      if (unbiased) {
        return theVariance / (l - 1);
      } else {
        return theVariance / l;
      }
    };
    /**
     * Computes the standard deviation of the given values
     * @param {Array} values
     * @param {boolean} [unbiased=true] - if true, divide by (n-1); if false, divide by n.
     * @returns {number}
     */


    exports.standardDeviation = function standardDeviation(values, unbiased) {
      return Math.sqrt(exports.variance(values, unbiased));
    };

    exports.standardError = function standardError(values) {
      return exports.standardDeviation(values) / Math.sqrt(values.length);
    };
    /**
     * IEEE Transactions on biomedical engineering, vol. 52, no. 1, january 2005, p. 76-
     * Calculate the standard deviation via the Median of the absolute deviation
     *  The formula for the standard deviation only holds for Gaussian random variables.
     * @returns {{mean: number, stdev: number}}
     */


    exports.robustMeanAndStdev = function robustMeanAndStdev(y) {
      var mean = 0,
          stdev = 0;
      var length = y.length,
          i = 0;

      for (i = 0; i < length; i++) {
        mean += y[i];
      }

      mean /= length;
      var averageDeviations = new Array(length);

      for (i = 0; i < length; i++) averageDeviations[i] = Math.abs(y[i] - mean);

      averageDeviations.sort(compareNumbers);

      if (length % 2 === 1) {
        stdev = averageDeviations[(length - 1) / 2] / 0.6745;
      } else {
        stdev = 0.5 * (averageDeviations[length / 2] + averageDeviations[length / 2 - 1]) / 0.6745;
      }

      return {
        mean: mean,
        stdev: stdev
      };
    };

    exports.quartiles = function quartiles(values, alreadySorted) {
      if (typeof alreadySorted === 'undefined') alreadySorted = false;

      if (!alreadySorted) {
        values = [].concat(values).sort(compareNumbers);
      }

      var quart = values.length / 4;
      var q1 = values[Math.ceil(quart) - 1];
      var q2 = exports.median(values, true);
      var q3 = values[Math.ceil(quart * 3) - 1];
      return {
        q1: q1,
        q2: q2,
        q3: q3
      };
    };

    exports.pooledStandardDeviation = function pooledStandardDeviation(samples, unbiased) {
      return Math.sqrt(exports.pooledVariance(samples, unbiased));
    };

    exports.pooledVariance = function pooledVariance(samples, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var sum = 0;
      var length = 0,
          l = samples.length;

      for (var i = 0; i < l; i++) {
        var values = samples[i];
        var vari = exports.variance(values);
        sum += (values.length - 1) * vari;
        if (unbiased) length += values.length - 1;else length += values.length;
      }

      return sum / length;
    };

    exports.mode = function mode(values) {
      var l = values.length,
          itemCount = new Array(l),
          i;

      for (i = 0; i < l; i++) {
        itemCount[i] = 0;
      }

      var itemArray = new Array(l);
      var count = 0;

      for (i = 0; i < l; i++) {
        var index = itemArray.indexOf(values[i]);
        if (index >= 0) itemCount[index]++;else {
          itemArray[count] = values[i];
          itemCount[count] = 1;
          count++;
        }
      }

      var maxValue = 0,
          maxIndex = 0;

      for (i = 0; i < count; i++) {
        if (itemCount[i] > maxValue) {
          maxValue = itemCount[i];
          maxIndex = i;
        }
      }

      return itemArray[maxIndex];
    };

    exports.covariance = function covariance(vector1, vector2, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var mean1 = exports.mean(vector1);
      var mean2 = exports.mean(vector2);
      if (vector1.length !== vector2.length) throw 'Vectors do not have the same dimensions';
      var cov = 0,
          l = vector1.length;

      for (var i = 0; i < l; i++) {
        var x = vector1[i] - mean1;
        var y = vector2[i] - mean2;
        cov += x * y;
      }

      if (unbiased) return cov / (l - 1);else return cov / l;
    };

    exports.skewness = function skewness(values, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var theMean = exports.mean(values);
      var s2 = 0,
          s3 = 0,
          l = values.length;

      for (var i = 0; i < l; i++) {
        var dev = values[i] - theMean;
        s2 += dev * dev;
        s3 += dev * dev * dev;
      }

      var m2 = s2 / l;
      var m3 = s3 / l;
      var g = m3 / Math.pow(m2, 3 / 2.0);

      if (unbiased) {
        var a = Math.sqrt(l * (l - 1));
        var b = l - 2;
        return a / b * g;
      } else {
        return g;
      }
    };

    exports.kurtosis = function kurtosis(values, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var theMean = exports.mean(values);
      var n = values.length,
          s2 = 0,
          s4 = 0;

      for (var i = 0; i < n; i++) {
        var dev = values[i] - theMean;
        s2 += dev * dev;
        s4 += dev * dev * dev * dev;
      }

      var m2 = s2 / n;
      var m4 = s4 / n;

      if (unbiased) {
        var v = s2 / (n - 1);
        var a = n * (n + 1) / ((n - 1) * (n - 2) * (n - 3));
        var b = s4 / (v * v);
        var c = (n - 1) * (n - 1) / ((n - 2) * (n - 3));
        return a * b - 3 * c;
      } else {
        return m4 / (m2 * m2) - 3;
      }
    };

    exports.entropy = function entropy(values, eps) {
      if (typeof eps === 'undefined') eps = 0;
      var sum = 0,
          l = values.length;

      for (var i = 0; i < l; i++) sum += values[i] * Math.log(values[i] + eps);

      return -sum;
    };

    exports.weightedMean = function weightedMean(values, weights) {
      var sum = 0,
          l = values.length;

      for (var i = 0; i < l; i++) sum += values[i] * weights[i];

      return sum;
    };

    exports.weightedStandardDeviation = function weightedStandardDeviation(values, weights) {
      return Math.sqrt(exports.weightedVariance(values, weights));
    };

    exports.weightedVariance = function weightedVariance(values, weights) {
      var theMean = exports.weightedMean(values, weights);
      var vari = 0,
          l = values.length;
      var a = 0,
          b = 0;

      for (var i = 0; i < l; i++) {
        var z = values[i] - theMean;
        var w = weights[i];
        vari += w * (z * z);
        b += w;
        a += w * w;
      }

      return vari * (b / (b * b - a));
    };

    exports.center = function center(values, inPlace) {
      if (typeof inPlace === 'undefined') inPlace = false;
      var result = values;
      if (!inPlace) result = [].concat(values);
      var theMean = exports.mean(result),
          l = result.length;

      for (var i = 0; i < l; i++) result[i] -= theMean;
    };

    exports.standardize = function standardize(values, standardDev, inPlace) {
      if (typeof standardDev === 'undefined') standardDev = exports.standardDeviation(values);
      if (typeof inPlace === 'undefined') inPlace = false;
      var l = values.length;
      var result = inPlace ? values : new Array(l);

      for (var i = 0; i < l; i++) result[i] = values[i] / standardDev;

      return result;
    };

    exports.cumulativeSum = function cumulativeSum(array) {
      var l = array.length;
      var result = new Array(l);
      result[0] = array[0];

      for (var i = 1; i < l; i++) result[i] = result[i - 1] + array[i];

      return result;
    };
  });

  var matrix$3 = createCommonjsModule$1(function (module, exports) {

    function compareNumbers(a, b) {
      return a - b;
    }

    exports.max = function max(matrix) {
      var max = -Infinity;

      for (var i = 0; i < matrix.length; i++) {
        for (var j = 0; j < matrix[i].length; j++) {
          if (matrix[i][j] > max) max = matrix[i][j];
        }
      }

      return max;
    };

    exports.min = function min(matrix) {
      var min = Infinity;

      for (var i = 0; i < matrix.length; i++) {
        for (var j = 0; j < matrix[i].length; j++) {
          if (matrix[i][j] < min) min = matrix[i][j];
        }
      }

      return min;
    };

    exports.minMax = function minMax(matrix) {
      var min = Infinity;
      var max = -Infinity;

      for (var i = 0; i < matrix.length; i++) {
        for (var j = 0; j < matrix[i].length; j++) {
          if (matrix[i][j] < min) min = matrix[i][j];
          if (matrix[i][j] > max) max = matrix[i][j];
        }
      }

      return {
        min: min,
        max: max
      };
    };

    exports.entropy = function entropy(matrix, eps) {
      if (typeof eps === 'undefined') {
        eps = 0;
      }

      var sum = 0,
          l1 = matrix.length,
          l2 = matrix[0].length;

      for (var i = 0; i < l1; i++) {
        for (var j = 0; j < l2; j++) {
          sum += matrix[i][j] * Math.log(matrix[i][j] + eps);
        }
      }

      return -sum;
    };

    exports.mean = function mean(matrix, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      var rows = matrix.length,
          cols = matrix[0].length,
          theMean,
          N,
          i,
          j;

      if (dimension === -1) {
        theMean = [0];
        N = rows * cols;

        for (i = 0; i < rows; i++) {
          for (j = 0; j < cols; j++) {
            theMean[0] += matrix[i][j];
          }
        }

        theMean[0] /= N;
      } else if (dimension === 0) {
        theMean = new Array(cols);
        N = rows;

        for (j = 0; j < cols; j++) {
          theMean[j] = 0;

          for (i = 0; i < rows; i++) {
            theMean[j] += matrix[i][j];
          }

          theMean[j] /= N;
        }
      } else if (dimension === 1) {
        theMean = new Array(rows);
        N = cols;

        for (j = 0; j < rows; j++) {
          theMean[j] = 0;

          for (i = 0; i < cols; i++) {
            theMean[j] += matrix[j][i];
          }

          theMean[j] /= N;
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return theMean;
    };

    exports.sum = function sum(matrix, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      var rows = matrix.length,
          cols = matrix[0].length,
          theSum,
          i,
          j;

      if (dimension === -1) {
        theSum = [0];

        for (i = 0; i < rows; i++) {
          for (j = 0; j < cols; j++) {
            theSum[0] += matrix[i][j];
          }
        }
      } else if (dimension === 0) {
        theSum = new Array(cols);

        for (j = 0; j < cols; j++) {
          theSum[j] = 0;

          for (i = 0; i < rows; i++) {
            theSum[j] += matrix[i][j];
          }
        }
      } else if (dimension === 1) {
        theSum = new Array(rows);

        for (j = 0; j < rows; j++) {
          theSum[j] = 0;

          for (i = 0; i < cols; i++) {
            theSum[j] += matrix[j][i];
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return theSum;
    };

    exports.product = function product(matrix, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      var rows = matrix.length,
          cols = matrix[0].length,
          theProduct,
          i,
          j;

      if (dimension === -1) {
        theProduct = [1];

        for (i = 0; i < rows; i++) {
          for (j = 0; j < cols; j++) {
            theProduct[0] *= matrix[i][j];
          }
        }
      } else if (dimension === 0) {
        theProduct = new Array(cols);

        for (j = 0; j < cols; j++) {
          theProduct[j] = 1;

          for (i = 0; i < rows; i++) {
            theProduct[j] *= matrix[i][j];
          }
        }
      } else if (dimension === 1) {
        theProduct = new Array(rows);

        for (j = 0; j < rows; j++) {
          theProduct[j] = 1;

          for (i = 0; i < cols; i++) {
            theProduct[j] *= matrix[j][i];
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return theProduct;
    };

    exports.standardDeviation = function standardDeviation(matrix, means, unbiased) {
      var vari = exports.variance(matrix, means, unbiased),
          l = vari.length;

      for (var i = 0; i < l; i++) {
        vari[i] = Math.sqrt(vari[i]);
      }

      return vari;
    };

    exports.variance = function variance(matrix, means, unbiased) {
      if (typeof unbiased === 'undefined') {
        unbiased = true;
      }

      means = means || exports.mean(matrix);
      var rows = matrix.length;
      if (rows === 0) return [];
      var cols = matrix[0].length;
      var vari = new Array(cols);

      for (var j = 0; j < cols; j++) {
        var sum1 = 0,
            sum2 = 0,
            x = 0;

        for (var i = 0; i < rows; i++) {
          x = matrix[i][j] - means[j];
          sum1 += x;
          sum2 += x * x;
        }

        if (unbiased) {
          vari[j] = (sum2 - sum1 * sum1 / rows) / (rows - 1);
        } else {
          vari[j] = (sum2 - sum1 * sum1 / rows) / rows;
        }
      }

      return vari;
    };

    exports.median = function median(matrix) {
      var rows = matrix.length,
          cols = matrix[0].length;
      var medians = new Array(cols);

      for (var i = 0; i < cols; i++) {
        var data = new Array(rows);

        for (var j = 0; j < rows; j++) {
          data[j] = matrix[j][i];
        }

        data.sort(compareNumbers);
        var N = data.length;

        if (N % 2 === 0) {
          medians[i] = (data[N / 2] + data[N / 2 - 1]) * 0.5;
        } else {
          medians[i] = data[Math.floor(N / 2)];
        }
      }

      return medians;
    };

    exports.mode = function mode(matrix) {
      var rows = matrix.length,
          cols = matrix[0].length,
          modes = new Array(cols),
          i,
          j;

      for (i = 0; i < cols; i++) {
        var itemCount = new Array(rows);

        for (var k = 0; k < rows; k++) {
          itemCount[k] = 0;
        }

        var itemArray = new Array(rows);
        var count = 0;

        for (j = 0; j < rows; j++) {
          var index = itemArray.indexOf(matrix[j][i]);

          if (index >= 0) {
            itemCount[index]++;
          } else {
            itemArray[count] = matrix[j][i];
            itemCount[count] = 1;
            count++;
          }
        }

        var maxValue = 0,
            maxIndex = 0;

        for (j = 0; j < count; j++) {
          if (itemCount[j] > maxValue) {
            maxValue = itemCount[j];
            maxIndex = j;
          }
        }

        modes[i] = itemArray[maxIndex];
      }

      return modes;
    };

    exports.skewness = function skewness(matrix, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var means = exports.mean(matrix);
      var n = matrix.length,
          l = means.length;
      var skew = new Array(l);

      for (var j = 0; j < l; j++) {
        var s2 = 0,
            s3 = 0;

        for (var i = 0; i < n; i++) {
          var dev = matrix[i][j] - means[j];
          s2 += dev * dev;
          s3 += dev * dev * dev;
        }

        var m2 = s2 / n;
        var m3 = s3 / n;
        var g = m3 / Math.pow(m2, 3 / 2);

        if (unbiased) {
          var a = Math.sqrt(n * (n - 1));
          var b = n - 2;
          skew[j] = a / b * g;
        } else {
          skew[j] = g;
        }
      }

      return skew;
    };

    exports.kurtosis = function kurtosis(matrix, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var means = exports.mean(matrix);
      var n = matrix.length,
          m = matrix[0].length;
      var kurt = new Array(m);

      for (var j = 0; j < m; j++) {
        var s2 = 0,
            s4 = 0;

        for (var i = 0; i < n; i++) {
          var dev = matrix[i][j] - means[j];
          s2 += dev * dev;
          s4 += dev * dev * dev * dev;
        }

        var m2 = s2 / n;
        var m4 = s4 / n;

        if (unbiased) {
          var v = s2 / (n - 1);
          var a = n * (n + 1) / ((n - 1) * (n - 2) * (n - 3));
          var b = s4 / (v * v);
          var c = (n - 1) * (n - 1) / ((n - 2) * (n - 3));
          kurt[j] = a * b - 3 * c;
        } else {
          kurt[j] = m4 / (m2 * m2) - 3;
        }
      }

      return kurt;
    };

    exports.standardError = function standardError(matrix) {
      var samples = matrix.length;
      var standardDeviations = exports.standardDeviation(matrix);
      var l = standardDeviations.length;
      var standardErrors = new Array(l);
      var sqrtN = Math.sqrt(samples);

      for (var i = 0; i < l; i++) {
        standardErrors[i] = standardDeviations[i] / sqrtN;
      }

      return standardErrors;
    };

    exports.covariance = function covariance(matrix, dimension) {
      return exports.scatter(matrix, undefined, dimension);
    };

    exports.scatter = function scatter(matrix, divisor, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      if (typeof divisor === 'undefined') {
        if (dimension === 0) {
          divisor = matrix.length - 1;
        } else if (dimension === 1) {
          divisor = matrix[0].length - 1;
        }
      }

      var means = exports.mean(matrix, dimension);
      var rows = matrix.length;

      if (rows === 0) {
        return [[]];
      }

      var cols = matrix[0].length,
          cov,
          i,
          j,
          s,
          k;

      if (dimension === 0) {
        cov = new Array(cols);

        for (i = 0; i < cols; i++) {
          cov[i] = new Array(cols);
        }

        for (i = 0; i < cols; i++) {
          for (j = i; j < cols; j++) {
            s = 0;

            for (k = 0; k < rows; k++) {
              s += (matrix[k][j] - means[j]) * (matrix[k][i] - means[i]);
            }

            s /= divisor;
            cov[i][j] = s;
            cov[j][i] = s;
          }
        }
      } else if (dimension === 1) {
        cov = new Array(rows);

        for (i = 0; i < rows; i++) {
          cov[i] = new Array(rows);
        }

        for (i = 0; i < rows; i++) {
          for (j = i; j < rows; j++) {
            s = 0;

            for (k = 0; k < cols; k++) {
              s += (matrix[j][k] - means[j]) * (matrix[i][k] - means[i]);
            }

            s /= divisor;
            cov[i][j] = s;
            cov[j][i] = s;
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return cov;
    };

    exports.correlation = function correlation(matrix) {
      var means = exports.mean(matrix),
          standardDeviations = exports.standardDeviation(matrix, true, means),
          scores = exports.zScores(matrix, means, standardDeviations),
          rows = matrix.length,
          cols = matrix[0].length,
          i,
          j;
      var cor = new Array(cols);

      for (i = 0; i < cols; i++) {
        cor[i] = new Array(cols);
      }

      for (i = 0; i < cols; i++) {
        for (j = i; j < cols; j++) {
          var c = 0;

          for (var k = 0, l = scores.length; k < l; k++) {
            c += scores[k][j] * scores[k][i];
          }

          c /= rows - 1;
          cor[i][j] = c;
          cor[j][i] = c;
        }
      }

      return cor;
    };

    exports.zScores = function zScores(matrix, means, standardDeviations) {
      means = means || exports.mean(matrix);
      if (typeof standardDeviations === 'undefined') standardDeviations = exports.standardDeviation(matrix, true, means);
      return exports.standardize(exports.center(matrix, means, false), standardDeviations, true);
    };

    exports.center = function center(matrix, means, inPlace) {
      means = means || exports.mean(matrix);
      var result = matrix,
          l = matrix.length,
          i,
          j,
          jj;

      if (!inPlace) {
        result = new Array(l);

        for (i = 0; i < l; i++) {
          result[i] = new Array(matrix[i].length);
        }
      }

      for (i = 0; i < l; i++) {
        var row = result[i];

        for (j = 0, jj = row.length; j < jj; j++) {
          row[j] = matrix[i][j] - means[j];
        }
      }

      return result;
    };

    exports.standardize = function standardize(matrix, standardDeviations, inPlace) {
      if (typeof standardDeviations === 'undefined') standardDeviations = exports.standardDeviation(matrix);
      var result = matrix,
          l = matrix.length,
          i,
          j,
          jj;

      if (!inPlace) {
        result = new Array(l);

        for (i = 0; i < l; i++) {
          result[i] = new Array(matrix[i].length);
        }
      }

      for (i = 0; i < l; i++) {
        var resultRow = result[i];
        var sourceRow = matrix[i];

        for (j = 0, jj = resultRow.length; j < jj; j++) {
          if (standardDeviations[j] !== 0 && !isNaN(standardDeviations[j])) {
            resultRow[j] = sourceRow[j] / standardDeviations[j];
          }
        }
      }

      return result;
    };

    exports.weightedVariance = function weightedVariance(matrix, weights) {
      var means = exports.mean(matrix);
      var rows = matrix.length;
      if (rows === 0) return [];
      var cols = matrix[0].length;
      var vari = new Array(cols);

      for (var j = 0; j < cols; j++) {
        var sum = 0;
        var a = 0,
            b = 0;

        for (var i = 0; i < rows; i++) {
          var z = matrix[i][j] - means[j];
          var w = weights[i];
          sum += w * (z * z);
          b += w;
          a += w * w;
        }

        vari[j] = sum * (b / (b * b - a));
      }

      return vari;
    };

    exports.weightedMean = function weightedMean(matrix, weights, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      var rows = matrix.length;
      if (rows === 0) return [];
      var cols = matrix[0].length,
          means,
          i,
          ii,
          j,
          w,
          row;

      if (dimension === 0) {
        means = new Array(cols);

        for (i = 0; i < cols; i++) {
          means[i] = 0;
        }

        for (i = 0; i < rows; i++) {
          row = matrix[i];
          w = weights[i];

          for (j = 0; j < cols; j++) {
            means[j] += row[j] * w;
          }
        }
      } else if (dimension === 1) {
        means = new Array(rows);

        for (i = 0; i < rows; i++) {
          means[i] = 0;
        }

        for (j = 0; j < rows; j++) {
          row = matrix[j];
          w = weights[j];

          for (i = 0; i < cols; i++) {
            means[j] += row[i] * w;
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      var weightSum = array$4.sum(weights);

      if (weightSum !== 0) {
        for (i = 0, ii = means.length; i < ii; i++) {
          means[i] /= weightSum;
        }
      }

      return means;
    };

    exports.weightedCovariance = function weightedCovariance(matrix, weights, means, dimension) {
      dimension = dimension || 0;
      means = means || exports.weightedMean(matrix, weights, dimension);
      var s1 = 0,
          s2 = 0;

      for (var i = 0, ii = weights.length; i < ii; i++) {
        s1 += weights[i];
        s2 += weights[i] * weights[i];
      }

      var factor = s1 / (s1 * s1 - s2);
      return exports.weightedScatter(matrix, weights, means, factor, dimension);
    };

    exports.weightedScatter = function weightedScatter(matrix, weights, means, factor, dimension) {
      dimension = dimension || 0;
      means = means || exports.weightedMean(matrix, weights, dimension);

      if (typeof factor === 'undefined') {
        factor = 1;
      }

      var rows = matrix.length;

      if (rows === 0) {
        return [[]];
      }

      var cols = matrix[0].length,
          cov,
          i,
          j,
          k,
          s;

      if (dimension === 0) {
        cov = new Array(cols);

        for (i = 0; i < cols; i++) {
          cov[i] = new Array(cols);
        }

        for (i = 0; i < cols; i++) {
          for (j = i; j < cols; j++) {
            s = 0;

            for (k = 0; k < rows; k++) {
              s += weights[k] * (matrix[k][j] - means[j]) * (matrix[k][i] - means[i]);
            }

            cov[i][j] = s * factor;
            cov[j][i] = s * factor;
          }
        }
      } else if (dimension === 1) {
        cov = new Array(rows);

        for (i = 0; i < rows; i++) {
          cov[i] = new Array(rows);
        }

        for (i = 0; i < rows; i++) {
          for (j = i; j < rows; j++) {
            s = 0;

            for (k = 0; k < cols; k++) {
              s += weights[k] * (matrix[j][k] - means[j]) * (matrix[i][k] - means[i]);
            }

            cov[i][j] = s * factor;
            cov[j][i] = s * factor;
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return cov;
    };
  });

  var array$3 = array$4;
  var matrix$2 = matrix$3;
  var mlStat$1 = {
    array: array$3,
    matrix: matrix$2
  };

  var COMMON_NO$1 = 0;
  var COMMON_FIRST$1 = 1;
  var COMMON_SECOND$1 = 2;
  var COMMON_BOTH$1 = 3; // should be a binary operation !

  var Stat$1 = mlStat$1.array;
  /**
   * Create a comparator class
   * {object} [options={}]
   * {string} [options.common=''] should we take only common peaks 'first', 'second', 'both', ''
   * {number} [options.widthBottom=2] bottom trapezoid width for similarity evaluation
   * {number} [options.widthTop=1] top trapezoid width for similarity evaluation
   * {number} [options.from] from region used for similarity calculation
   * {number} [options.to] to region used for similarity calculation
   */

  var src$n = function Comparator(options = {}) {
    var widthTop, widthBottom, from, to;
    var array1Extract, array2Extract, widthSlope, array1ExtractInfo, array2ExtractInfo;
    var common, commonFactor;
    setOptions(options);
    var array1 = [];
    var array2 = [];
    /*
       2 formats are allowed:
       [[x1,x2,...],[y1,y2,...]] or [[x1,y1],[x2,y2], ...]
      */

    function setOptions(newOptions) {
      options = newOptions || {};

      if (typeof options.common === 'string') {
        if (options.common.toLowerCase() === 'first') {
          common = COMMON_FIRST$1;
        } else if (options.common.toLowerCase() === 'second') {
          common = COMMON_SECOND$1;
        } else if (options.common.toLowerCase() === 'both') {
          common = COMMON_BOTH$1;
        } else {
          common = COMMON_NO$1;
        }
      } else {
        if (options.common === true) {
          common = COMMON_BOTH$1;
        } else {
          common = COMMON_NO$1;
        }
      }

      commonFactor = options.commonFactor || commonFactor || 4;

      if (options.widthBottom === undefined) {
        options.widthBottom = widthBottom || 2;
      }

      if (options.widthTop === undefined) {
        options.widthTop = widthTop || 1;
      }

      setTrapezoid(options.widthBottom, options.widthTop);
      setFromTo(options.from || from, options.to || to);
    }

    function setPeaks1(anArray) {
      array1 = checkArray(anArray);

      if (common) {
        var extracts = commonExtractAndNormalize$1(array1, array2, widthBottom, from, to, common);
        array1Extract = extracts.data1;
        array1ExtractInfo = extracts.info1;
        array2Extract = extracts.data2;
        array2ExtractInfo = extracts.info2;
      } else {
        var extract = extractAndNormalize$1(array1, from, to);
        array1Extract = extract.data;
        array1ExtractInfo = extract.info;
      }
    }

    function setPeaks2(anArray) {
      array2 = checkArray(anArray);

      if (common) {
        var extracts = commonExtractAndNormalize$1(array1, array2, widthBottom, from, to, common);
        array1Extract = extracts.data1;
        array1ExtractInfo = extracts.info1;
        array2Extract = extracts.data2;
        array2ExtractInfo = extracts.info2;
      } else {
        var extract = extractAndNormalize$1(array2, from, to);
        array2Extract = extract.data;
        array2ExtractInfo = extract.info;
      }
    }

    function getExtract1() {
      return array1Extract;
    }

    function getExtract2() {
      return array2Extract;
    }

    function getExtractInfo1() {
      return array1ExtractInfo;
    }

    function getExtractInfo2() {
      return array2ExtractInfo;
    }

    function setTrapezoid(newWidthBottom, newWidthTop) {
      widthTop = newWidthTop;
      widthBottom = newWidthBottom;
      widthSlope = (widthBottom - widthTop) / 2;
      if (widthBottom < widthTop) throw new Error('widthBottom has to be larger than widthTop');
    }

    function setFromTo(newFrom, newTo) {
      if (newFrom === from && newTo === to) return;
      from = newFrom;
      to = newTo;

      if (common) {
        var extracts = commonExtractAndNormalize$1(array1, array2, widthBottom, from, to, common);
        array1Extract = extracts.data1;
        array1ExtractInfo = extracts.info1;
        array2Extract = extracts.data2;
        array2ExtractInfo = extracts.info2;
      } else {
        var extract = extractAndNormalize$1(array1, from, to);
        array1Extract = extract.data;
        array1ExtractInfo = extract.info;
        extract = extractAndNormalize$1(array2, from, to);
        array2Extract = extract.data;
        array2ExtractInfo = extract.info;
      }
    }

    function getOverlap(x1, y1, x2, y2) {
      if (y1 === 0 || y2 === 0) return 0; // TAKE CARE !!! We multiply the diff by 2 !!!

      var diff = Math.abs(x1 - x2) * 2;
      if (diff > widthBottom) return 0;

      if (diff <= widthTop) {
        return Math.min(y1, y2);
      }

      var maxValue = Math.max(y1, y2) * (widthBottom - diff) / (widthBottom - widthTop);
      return Math.min(y1, y2, maxValue);
    } // This is the old trapezoid similarity


    function getOverlapTrapezoid(x1, y1, x2, y2) {
      var factor = 2 / (widthTop + widthBottom); // correction for surface=1

      if (y1 === 0 || y2 === 0) return 0;

      if (x1 === x2) {
        // they have the same position
        return Math.min(y1, y2);
      }

      var diff = Math.abs(x1 - x2);
      if (diff >= widthBottom) return 0;

      if (y1 === y2) {
        // do they have the same height ???
        // we need to find the common length
        if (diff <= widthTop) {
          return ((widthTop + widthBottom) / 2 - diff) * y1 * factor;
        } else if (diff <= widthBottom) {
          return (widthBottom - diff) * y1 / 2 * (diff - widthTop) / (widthBottom - widthTop) * factor;
        }

        return 0;
      } else {
        // the height are different and not the same position ...
        // we need to consider only one segment to find its intersection
        var small = Math.min(y1, y2);
        var big = Math.max(y1, y2);
        var targets = [[[0, 0], [widthSlope, small]], [[widthSlope, small], [widthSlope + widthTop, small]], [[widthTop + widthSlope, small], [widthBottom, 0]]];
        var segment;

        if (x1 > x2 && y1 > y2 || x1 < x2 && y1 < y2) {
          segment = [[diff, 0], [diff + widthSlope, big]];
        } else {
          segment = [[diff + widthSlope, big], [diff, 0]];
        }

        for (var i = 0; i < 3; i++) {
          var intersection = getIntersection$1(targets[i], segment);

          if (intersection) {
            switch (i) {
              case 0:
                return small - diff * intersection.y / 2 * factor;

              case 1:
                // to simplify ...
                //     console.log("           ",widthSlope,small,big,intersection.x)
                return (widthSlope * small / (2 * big) * small + (widthTop + widthSlope - intersection.x) * small + widthSlope * small / 2) * factor;

              case 2:
                return (widthBottom - diff) * intersection.y / 2 * factor;

              default:
                throw new Error(`unexpected intersection value: ${i}`);
            }
          }
        }
      }

      return NaN;
    } // this method calculates the total diff. The sum of positive value will yield to overlap


    function calculateDiff() {
      // we need to take 2 pointers
      // and travel progressively between them ...
      var newFirst = [[].concat(array1Extract[0]), [].concat(array1Extract[1])];
      var newSecond = [[].concat(array2Extract[0]), [].concat(array2Extract[1])];
      var array1Length = array1Extract[0] ? array1Extract[0].length : 0;
      var array2Length = array2Extract[0] ? array2Extract[0].length : 0;
      var pos1 = 0;
      var pos2 = 0;
      var previous2 = 0;

      while (pos1 < array1Length) {
        var diff = newFirst[0][pos1] - array2Extract[0][pos2];

        if (Math.abs(diff) < widthBottom) {
          // there is some overlap
          var overlap;

          if (options.trapezoid) {
            overlap = getOverlapTrapezoid(newFirst[0][pos1], newFirst[1][pos1], newSecond[0][pos2], newSecond[1][pos2]);
          } else {
            overlap = getOverlap(newFirst[0][pos1], newFirst[1][pos1], newSecond[0][pos2], newSecond[1][pos2]);
          }

          newFirst[1][pos1] -= overlap;
          newSecond[1][pos2] -= overlap;

          if (pos2 < array2Length - 1) {
            pos2++;
          } else {
            pos1++;
            pos2 = previous2;
          }
        } else {
          if (diff > 0 && pos2 < array2Length - 1) {
            pos2++;
            previous2 = pos2;
          } else {
            pos1++;
            pos2 = previous2;
          }
        }
      }

      return newSecond;
    }
    /*
          This code requires the use of an array like  [[x1,y1],[x2,y2], ...]
          If it is not the right format, we will just convert it
          Otherwise we return the correct format
       */


    function checkArray(points) {
      // if it is already a 2D array of points, we just return them
      if (Array.isArray(points) && Array.isArray(points[0]) && points.length === 2) return points;
      var x = new Array(points.length);
      var y = new Array(points.length);

      for (var i = 0; i < points.length; i++) {
        x[i] = points[i][0];
        y[i] = points[i][1];
      }

      return [x, y];
    }

    function getSimilarity(newPeaks1, newPeaks2) {
      if (newPeaks1) setPeaks1(newPeaks1);
      if (newPeaks2) setPeaks2(newPeaks2);
      var result = {};
      result.diff = calculateDiff();
      result.extract1 = getExtract1();
      result.extract2 = getExtract2();
      result.extractInfo1 = getExtractInfo1();
      result.extractInfo2 = getExtractInfo2();
      result.similarity = calculateOverlapFromDiff$1(result.diff);
      result.widthBottom = widthBottom;
      result.widthTop = widthTop;
      return result;
    }
    /*
      This works mainly when you have a array1 that is fixed
      newPeaks2 have to be normalized ! (sum to 1)
    */


    function fastSimilarity(newPeaks2, from, to) {
      array1Extract = extract$1(array1, from, to);
      array2Extract = newPeaks2;
      if (common & COMMON_SECOND$1) array1Extract = getCommonArray$1(array1Extract, array2Extract, widthBottom);
      normalize$5(array1Extract);
      var diff = calculateDiff();
      return calculateOverlapFromDiff$1(diff);
    }

    this.setPeaks1 = setPeaks1;
    this.setPeaks2 = setPeaks2;
    this.getExtract1 = getExtract1;
    this.getExtract2 = getExtract2;
    this.getExtractInfo1 = getExtractInfo1;
    this.getExtractInfo2 = getExtractInfo2;
    this.setFromTo = setFromTo;
    this.setOptions = setOptions;
    this.setTrapezoid = setTrapezoid;
    this.getSimilarity = getSimilarity;
    this.getCommonArray = getCommonArray$1;
    this.fastSimilarity = fastSimilarity;
  }; // returns an new array based on array1 where there is a peak of array2 at a distance under width/2


  function getCommonArray$1(array1, array2, width) {
    var newArray = [[], []];
    var pos2 = 0;
    width /= 2;
    var j = 0;
    var array1Length = array1[0] ? array1[0].length : 0;
    var array2Length = array2[0] ? array2[0].length : 0;

    for (var i = 0; i < array1Length; i++) {
      while (pos2 < array2Length && array1[0][i] > array2[0][pos2] + width) {
        pos2++;
      }

      if (pos2 < array2Length && array1[0][i] > array2[0][pos2] - width) {
        newArray[0][j] = array1[0][i];
        newArray[1][j] = array1[1][i];
        j++;
      }
    }

    return newArray;
  } // Adapted from: http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/1968345#1968345


  function getIntersection$1(segment1, segment2) {
    var p0X = segment1[0][0];
    var p0Y = segment1[0][1];
    var p1X = segment1[1][0];
    var p1Y = segment1[1][1];
    var p2X = segment2[0][0];
    var p2Y = segment2[0][1];
    var p3X = segment2[1][0];
    var p3Y = segment2[1][1];
    var s1X, s1Y, s2X, s2Y;
    s1X = p1X - p0X;
    s1Y = p1Y - p0Y;
    s2X = p3X - p2X;
    s2Y = p3Y - p2Y;
    var s, t;
    s = (-s1Y * (p0X - p2X) + s1X * (p0Y - p2Y)) / (-s2X * s1Y + s1X * s2Y);
    t = (s2X * (p0Y - p2Y) - s2Y * (p0X - p2X)) / (-s2X * s1Y + s1X * s2Y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
      return {
        x: p0X + t * s1X,
        y: p0Y + t * s1Y
      };
    }

    return null; // No collision
  }

  function normalize$5(array) {
    var min = Stat$1.min(array[1]);
    var max = Stat$1.max(array[1]);
    var sum = Stat$1.sum(array[1]);
    var length = array[1] ? array[1].length : 0;

    if (sum !== 0) {
      for (var i = 0; i < length; i++) {
        array[1][i] /= sum;
      }
    }

    return {
      sum: sum,
      min: min,
      max: max
    };
  } // this method will systematically take care of both array


  function commonExtractAndNormalize$1(array1, array2, width, from, to, common) {
    if (!Array.isArray(array1) || !Array.isArray(array2)) {
      return {
        info: undefined,
        data: undefined
      };
    }

    var extract1 = extract$1(array1, from, to);
    var extract2 = extract$1(array2, from, to);
    var common1, common2, info1, info2;

    if (common & COMMON_SECOND$1) {
      common1 = getCommonArray$1(extract1, extract2, width);
      info1 = normalize$5(common1);
    } else {
      common1 = extract1;
      info1 = normalize$5(common1);
    }

    if (common & COMMON_FIRST$1) {
      common2 = getCommonArray$1(extract2, extract1, width);
      info2 = normalize$5(common2);
    } else {
      common2 = extract2;
      info2 = normalize$5(common2);
    }

    return {
      info1: info1,
      info2: info2,
      data1: common1,
      data2: common2
    };
  }

  function extract$1(array, from, to) {
    var newArray = [[], []];
    var j = 0;
    var length = array[0] ? array[0].length : 0;

    for (var i = 0; i < length; i++) {
      if ((!from || array[0][i] >= from) && (!to || array[0][i] <= to)) {
        newArray[0][j] = array[0][i];
        newArray[1][j] = array[1][i];
        j++;
      }
    }

    return newArray;
  }

  function extractAndNormalize$1(array, from, to) {
    if (!Array.isArray(array)) {
      return {
        info: undefined,
        data: undefined
      };
    }

    var newArray = extract$1(array, from, to);
    var info = normalize$5(newArray);
    return {
      info: info,
      data: newArray
    };
  }

  function calculateOverlapFromDiff$1(diffs) {
    if (diffs[1].length === 0) return 0;
    var sumPos = 0;

    for (var i = 0; i < diffs[1].length; i++) {
      sumPos += Math.abs(diffs[1][i]);
    }

    return 1 - sumPos;
  }

  /**
   * @param {object}   [options={}]
   * @param {object}   [options.minCharge=1]
   * @param {object}   [options.maxCharge=10]
   * @param {object}   [options.similarity={}]
   * @param {object}   [options.similarity.widthBottom]
   * @param {object}   [options.similarity.widthTop]
   * @param {object}   [options.similarity.widthFunction] - function called with mass that should return an object width containing top and bottom
   * @param {object}   [options.similarity.zone={}]
   * @param {object}   [options.similarity.zone.low=-0.5] - window shift based on observed monoisotopic mass
   * @param {object}   [options.similarity.zone.high=2.5] - to value for the comparison window
   * @param {object}   [options.similarity.common]
   */


  const NEUTRON_MASS$1 = 1;

  function getPeakChargeBySimilarity(spectrum, targetMass, options = {}) {
    let {
      similarity = {},
      minCharge = 1,
      maxCharge = 10
    } = options;
    let {
      zone = {},
      widthFunction
    } = similarity;
    let {
      low = -0.5,
      high = 2.5
    } = zone;

    if (!spectrum || !spectrum.data.x.length > 0) {
      throw Error('You need to add an experimental spectrum first using setMassSpectrum');
    }

    let width = {
      bottom: similarity.widthBottom,
      top: similarity.widthTop
    };
    similarity = JSON.parse(JSON.stringify(similarity));
    similarity.common = 'second';
    let experimentalData = spectrum.data;
    let similarityProcessor = new src$n(similarity);
    similarityProcessor.setPeaks1([experimentalData.x, experimentalData.y]);

    if (widthFunction && typeof widthFunction === 'string') {
      // eslint-disable-next-line no-new-func
      widthFunction = new Function('mass', widthFunction);
      let checkTopBottom = widthFunction(123);

      if (!checkTopBottom.bottom || !checkTopBottom.top) {
        throw Error('widthFunction should return an object with bottom and top properties');
      }
    }

    let fromCharge = minCharge * maxCharge > 0 ? Math.round(Math.min(Math.abs(minCharge), Math.abs(maxCharge))) : 1;
    let toCharge = Math.round(Math.max(Math.abs(minCharge), Math.abs(maxCharge)));
    let fromIsotope = Math.ceil(low);
    let toIsotope = Math.floor(high);
    let isotopeHeight = 1 / (toIsotope - fromIsotope + 1);
    let results = [];

    for (let charge = fromCharge; charge < toCharge + 1; charge++) {
      let isotopePositions = {
        x: [],
        y: []
      };

      for (let isotopePosition = fromIsotope; isotopePosition < toIsotope + 1; isotopePosition++) {
        isotopePositions.x.push(targetMass + isotopePosition * NEUTRON_MASS$1 / charge);
        isotopePositions.y.push(isotopeHeight);
      }

      let from = targetMass + low / Math.abs(charge);
      let to = targetMass + high / Math.abs(charge);
      similarityProcessor.setFromTo(from, to);

      if (widthFunction) {
        width = widthFunction(targetMass);
        similarityProcessor.setTrapezoid(width.bottom, width.top);
      }

      similarityProcessor.setPeaks2([isotopePositions.x, isotopePositions.y]);
      let result = similarityProcessor.getSimilarity();
      results.push({
        charge,
        similarity: result.similarity
      });
    }

    return results.sort((a, b) => b.similarity - a.similarity)[0].charge;
  }

  var getPeakChargeBySimilarity_1 = getPeakChargeBySimilarity;

  /**
   * Filter the array of peaks
   * @param {array} peaks - array of all the peaks
   * @param {object} [options={}]
   * @param {number} [options.from] - min X value of the window to consider
   * @param {number} [options.to] - max X value of the window to consider
   * @param {number} [options.threshold=0.01] - minimal intensity compare to base peak
   * @param {number} [options.limit=undefined] - maximal number of peaks (based on intensity)
   * @returns {array} - copy of peaks with 'close' annotation
   */

  function getPeaks$1(peaks, options = {}) {
    const {
      from = peaks.reduce((previous, peak) => Math.min(peak.x, previous), Number.MAX_SAFE_INTEGER),
      to = peaks.reduce((previous, peak) => Math.max(peak.x, previous), Number.MIN_SAFE_INTEGER),
      threshold = 0.01,
      limit
    } = options;
    let maxY = Number.MIN_SAFE_INTEGER;

    for (let peak of peaks) {
      if (peak.y > maxY) maxY = peak.y;
    }

    let minY = maxY * threshold;
    peaks = peaks.filter(peak => peak.x >= from && peak.x <= to && peak.y >= minY);

    if (limit && peaks.length > limit) {
      peaks.sort((a, b) => b.y - a.y);
      peaks = peaks.slice(0, limit);
    }

    return peaks.sort((a, b) => a.x - b.x);
  }

  var getPeaks_1 = getPeaks$1;

  /**
   * When a spectrum is continous ?
   * - has more than 100 points
   * - deltaX change can not be more than a factor 2
   * - deltaX may not be larger than 0.1
   * - if y is zero it does not count
   * @param {object} spectrum
   * @param {object} [options={}]
   * @param {number} [options.minLength=100]
   * @param {number} [options.maxDeltaRatio=3]
   */

  function isContinuous(spectrum, options = {}) {
    const {
      minLength = 100,
      maxDeltaRatio = 3
    } = options;
    const minRadio = 1 / maxDeltaRatio;
    const maxRatio = 1 * maxDeltaRatio;

    if (spectrum.continuous === undefined) {
      let xs = spectrum.data.x;
      let ys = spectrum.data.y;

      if (xs.length < minLength) {
        spectrum.continuous = false;
      } else {
        let previousDelta = xs[1] - xs[0];
        spectrum.continuous = true;
        let success = 0;
        let failed = 0;

        for (let i = 0; i < xs.length - 1; i++) {
          if (ys[i] === 0 || ys[i + 1] === 0) {
            previousDelta = 0;
            continue;
          }

          let delta = xs[i + 1] - xs[i];

          if (previousDelta) {
            let ratio = delta / previousDelta;

            if ((Math.abs(delta) > 0.1 || ratio < minRadio || ratio > maxRatio) && ys[i] !== 0 && ys[i + 1] !== 0) {
              failed++;
              break;
            } else {
              success++;
            }
          }

          previousDelta = delta;
        }

        if (success / failed < 10) {
          spectrum.continuous = false;
        }
      }
    }

    return spectrum.continuous;
  }

  var isContinuous_1 = isContinuous;

  /**
   * @param {object}   [options={}]
   * @param {object}   [options.min=1]
   * @param {object}   [options.max=10]
   * @param {object}   [options.low=-1]
   * @param {object}   [options.high=1]
   * @param {object}   [options.precision=100]
   */

  const NEUTRON_MASS = 1;

  function appendPeaksCharge(peaks, options = {}) {
    let {
      precision = 100,
      low = -1,
      high = 1,
      min: minCharge = 1,
      max: maxCharge = 10
    } = options;
    let fromCharge = minCharge * maxCharge > 0 ? Math.round(Math.min(Math.abs(minCharge), Math.abs(maxCharge))) : 1;
    let toCharge = Math.round(Math.max(Math.abs(minCharge), Math.abs(maxCharge)));
    let fromIsotope = Math.ceil(low);
    let toIsotope = Math.floor(high);
    let numberIsotopes = toIsotope - fromIsotope + 1;
    let isotopeIntensity = 1 / numberIsotopes;
    let fromIndex = 0;
    let localFromIndex = 0;
    let localToIndex = 0;

    for (let peakIndex = 0; peakIndex < peaks.length; peakIndex++) {
      let peak = peaks[peakIndex];
      let targetMass = peak.x;
      localFromIndex = fromIndex;
      let bestCharge = fromCharge;
      let bestChargeMatch = 0;

      for (let charge = fromCharge; charge < toCharge + 1; charge++) {
        let theoreticalPositions = {
          x: [],
          y: new Array(numberIsotopes).fill(isotopeIntensity)
        };
        let massRange = precision * 1e-6 * targetMass;

        for (let isotopePosition = fromIsotope; isotopePosition < toIsotope + 1; isotopePosition++) {
          theoreticalPositions.x.push(targetMass + isotopePosition * NEUTRON_MASS / charge);
        }

        let fromMass = targetMass + low / Math.abs(charge) - massRange;
        let toMass = targetMass + high / Math.abs(charge) + massRange;

        if (charge === 1) {
          // we may move the fromIndex
          while (peaks[fromIndex].x < fromMass) {
            fromIndex++;
          }
        }
        /*
         * Find the from / to index for the specific peak and specific charge
         */


        while (peaks[localFromIndex].x < fromMass) {
          localFromIndex++;
        }

        localToIndex = localFromIndex;
        let localHeightSum = 0;

        while (localToIndex < peaks.length && peaks[localToIndex].x < toMass) {
          localHeightSum += peaks[localToIndex].y;
          localToIndex++;
        }

        localToIndex--; //  console.log({ localFromIndex, localToIndex });

        /*
          Calculate the overlap for a specific peak and specific charge
        */

        let currentTheoreticalPosition = 0;
        let theoreticalMaxValue = 1 / numberIsotopes;
        let totalMatch = 0;

        for (let index = localFromIndex; index <= localToIndex; index++) {
          let minMass = theoreticalPositions.x[currentTheoreticalPosition] - massRange / charge;
          let maxMass = theoreticalPositions.x[currentTheoreticalPosition] + massRange / charge;

          while (maxMass < peaks[index].x) {
            currentTheoreticalPosition++;
            theoreticalMaxValue = 1 / numberIsotopes;
            minMass = theoreticalPositions.x[currentTheoreticalPosition] - massRange / charge;
            maxMass = theoreticalPositions.x[currentTheoreticalPosition] + massRange / charge;
          }

          while (index < peaks.length && peaks[index].x < minMass) {
            index++;
          } //    console.log({ index, minMass, maxMass, massRange, localHeightSum });


          if (index < peaks.length && peaks[index].x <= maxMass) {
            while (index < peaks.length && peaks[index].x <= maxMass) {
              if (peaks[index].x >= minMass && peaks[index].x <= maxMass) {
                let value = peaks[index].y / localHeightSum; //      console.log({ theoreticalMaxValue, value });

                value = Math.min(theoreticalMaxValue, value);
                theoreticalMaxValue -= value;
                totalMatch += value;
              }

              index++;
            }

            index--;
          }

          if (totalMatch > bestChargeMatch) {
            bestCharge = charge;
            bestChargeMatch = totalMatch;
          }
        }
      }

      peak.charge = bestCharge;
    }

    return peaks;
  }

  var appendPeaksCharge_1 = appendPeaksCharge;

  var require$$0$5 = /*@__PURE__*/getAugmentedNamespace(src$p);

  const gsd$1 = require$$0$5.gsd;
  /**
   * Filter the array of peaks
   * @param {Spectrum} spectrum - array of all the peaks
   * @param {object} [options={}]
   * @param {object} [options.charge={}]
   * @param {number} [options.charge.min=1]
   * @param {number} [options.charge.max=10]
   * @param {number} [options.charge.low=-1]
   * @param {number} [options.charge.high=1]
   * @param {number} [options.charge.precision=30]
   * @returns {array} - copy of peaks with 'close' annotation
   */

  function peakPicking(spectrum, options = {}) {
    const {
      charge: chargeOptions = {}
    } = options;

    if (!spectrum.peaks) {
      if (spectrum.isContinuous()) {
        spectrum.peaks = gsd$1(spectrum.data, {
          noiseLevel: 0,
          minMaxRatio: 0.00025,
          // Threshold to determine if a given peak should be considered as a noise
          realTopDetection: true,
          maxCriteria: true,
          // inverted:false
          smoothY: false,
          sgOptions: {
            windowSize: 7,
            polynomial: 3
          }
        });
      } else {
        spectrum.peaks = [];
        let data = spectrum.data;

        for (let i = 0; i < data.x.length; i++) {
          spectrum.peaks.push({
            x: data.x[i],
            y: data.y[i],
            width: 0
          });
        }
      } // required and linked to https://github.com/mljs/global-spectral-deconvolution/issues/17


      spectrum.peaks = spectrum.peaks.filter(peak => !isNaN(peak.x) && !isNaN(peak.y));
      appendPeaksCharge_1(spectrum.peaks, chargeOptions);
    }

    return spectrum.peaks;
  }

  var peakPicking_1 = peakPicking;

  function _interopDefaultLegacy$3(e) {
    return e && typeof e === 'object' && 'default' in e ? e : {
      'default': e
    };
  }

  var isArray__default$2 = /*#__PURE__*/_interopDefaultLegacy$3(isArray$2);

  function min$7(input, options = {}) {
    if (!isArray__default$2['default'](input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }

    const {
      fromIndex = 0,
      toIndex = input.length
    } = options;

    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');
    }

    let minValue = input[fromIndex];

    for (let i = fromIndex + 1; i < toIndex; i++) {
      if (input[i] < minValue) minValue = input[i];
    }

    return minValue;
  }

  var lib$5 = min$7;

  function maybeToPrecision$1(value, digits) {
    if (value < 0) {
      value = 0 - value;

      if (typeof digits === 'number') {
        return `- ${value.toPrecision(digits)}`;
      } else {
        return `- ${value.toString()}`;
      }
    } else {
      if (typeof digits === 'number') {
        return value.toPrecision(digits);
      } else {
        return value.toString();
      }
    }
  }

  function checkArraySize$1(x, y) {
    if (!isAnyArray$7(x) || !isAnyArray$7(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$3 {
    constructor() {
      if (new.target === BaseRegression$3) {
        throw new Error('BaseRegression must be subclassed');
      }
    }

    predict(x) {
      if (typeof x === 'number') {
        return this._predict(x);
      } else if (isAnyArray$7(x)) {
        const y = [];

        for (let i = 0; i < x.length; i++) {
          y.push(this._predict(x[i]));
        }

        return y;
      } else {
        throw new TypeError('x must be a number or array');
      }
    }

    _predict() {
      throw new Error('_predict must be implemented');
    }

    train() {// Do nothing for this package
    }

    toString() {
      return '';
    }

    toLaTeX() {
      return '';
    }
    /**
     * Return the correlation coefficient of determination (r) and chi-square.
     * @param {Array<number>} x
     * @param {Array<number>} y
     * @return {object}
     */


    score(x, y) {
      if (!isAnyArray$7(x) || !isAnyArray$7(y) || x.length !== y.length) {
        throw new Error('x and y must be arrays of the same length');
      }

      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: r,
        r2: r * r,
        chi2: chi2,
        rmsd: Math.sqrt(rmsd / n)
      };
    }

  }

  var src$m = /*#__PURE__*/Object.freeze({
    __proto__: null,
    'default': BaseRegression$3,
    maybeToPrecision: maybeToPrecision$1,
    checkArrayLength: checkArraySize$1
  });

  class SimpleLinearRegression$1 extends BaseRegression$3 {
    constructor(x, y) {
      super();

      if (x === true) {
        this.slope = y.slope;
        this.intercept = y.intercept;
        this.coefficients = [y.intercept, y.slope];
      } else {
        checkArraySize$1(x, y);
        regress$1(this, x, y);
      }
    }

    toJSON() {
      return {
        name: 'simpleLinearRegression',
        slope: this.slope,
        intercept: this.intercept
      };
    }

    _predict(x) {
      return this.slope * x + this.intercept;
    }

    computeX(y) {
      return (y - this.intercept) / this.slope;
    }

    toString(precision) {
      let result = 'f(x) = ';

      if (this.slope !== 0) {
        const xFactor = maybeToPrecision$1(this.slope, precision);
        result += `${xFactor === '1' ? '' : `${xFactor} * `}x`;

        if (this.intercept !== 0) {
          const absIntercept = Math.abs(this.intercept);
          const operator = absIntercept === this.intercept ? '+' : '-';
          result += ` ${operator} ${maybeToPrecision$1(absIntercept, precision)}`;
        }
      } else {
        result += maybeToPrecision$1(this.intercept, precision);
      }

      return result;
    }

    toLaTeX(precision) {
      return this.toString(precision);
    }

    static load(json) {
      if (json.name !== 'simpleLinearRegression') {
        throw new TypeError('not a SLR model');
      }

      return new SimpleLinearRegression$1(true, json);
    }

  }

  function regress$1(slr, x, y) {
    const n = x.length;
    let xSum = 0;
    let ySum = 0;
    let xSquared = 0;
    let xY = 0;

    for (let i = 0; i < n; i++) {
      xSum += x[i];
      ySum += y[i];
      xSquared += x[i] * x[i];
      xY += x[i] * y[i];
    }

    const numerator = n * xY - xSum * ySum;
    slr.slope = numerator / (n * xSquared - xSum * xSum);
    slr.intercept = 1 / n * ySum - slr.slope * (1 / n) * xSum;
    slr.coefficients = [slr.intercept, slr.slope];
  }

  var src$l = /*#__PURE__*/Object.freeze({
    __proto__: null,
    'default': SimpleLinearRegression$1
  });

  var BaseRegression$2 = /*@__PURE__*/getAugmentedNamespace(src$m);

  var require$$0$4 = /*@__PURE__*/getAugmentedNamespace(src$l);

  function _interopDefault$2(ex) {
    return ex && typeof ex === 'object' && 'default' in ex ? ex['default'] : ex;
  }

  var BaseRegression__default$1 = _interopDefault$2(BaseRegression$2);

  var SimpleLinearRegression = _interopDefault$2(require$$0$4);

  class PowerRegression extends BaseRegression__default$1 {
    constructor(x, y) {
      super();

      if (x === true) {
        // reloading model
        this.A = y.A;
        this.B = y.B;
      } else {
        BaseRegression$2.checkArrayLength(x, y);
        regress(this, x, y);
      }
    }

    _predict(newInputs) {
      return this.A * Math.pow(newInputs, this.B);
    }

    toJSON() {
      return {
        name: 'powerRegression',
        A: this.A,
        B: this.B
      };
    }

    toString(precision) {
      return `f(x) = ${BaseRegression$2.maybeToPrecision(this.A, precision)} * x^${BaseRegression$2.maybeToPrecision(this.B, precision)}`;
    }

    toLaTeX(precision) {
      let latex = '';

      if (this.B >= 0) {
        latex = `f(x) = ${BaseRegression$2.maybeToPrecision(this.A, precision)}x^{${BaseRegression$2.maybeToPrecision(this.B, precision)}}`;
      } else {
        latex = `f(x) = \\frac{${BaseRegression$2.maybeToPrecision(this.A, precision)}}{x^{${BaseRegression$2.maybeToPrecision(-this.B, precision)}}}`;
      }

      latex = latex.replace(/e([+-]?[0-9]+)/g, 'e^{$1}');
      return latex;
    }

    static load(json) {
      if (json.name !== 'powerRegression') {
        throw new TypeError('not a power regression model');
      }

      return new PowerRegression(true, json);
    }

  }

  function regress(pr, x, y) {
    const n = x.length;
    const xl = new Array(n);
    const yl = new Array(n);

    for (let i = 0; i < n; i++) {
      xl[i] = Math.log(x[i]);
      yl[i] = Math.log(y[i]);
    }

    const linear = new SimpleLinearRegression(xl, yl);
    pr.A = Math.exp(linear.intercept);
    pr.B = linear.slope;
  }

  var lib$4 = PowerRegression;

  function peaksWidth(peaks) {
    let xs = peaks.map(peak => peak.x);
    let widths = peaks.map(peak => peak.width);

    if (xs.length < 2) {
      throw new Error(`peaksWidth: not enough peaks (less than 2) for automatic width calculation: ${xs.length}`);
    }

    let regression = new lib$4(xs, widths, {
      computeQuality: true,
      computeCoefficient: true
    });

    if (isNaN(regression.A) || isNaN(regression.B)) {
      throw new Error('peaksWidth: can not calculate regression');
    }

    let from = lib$5(xs);
    let to = lib$7(xs);
    let regressionChart = {
      x: [],
      y: []
    };

    for (let x = from; x <= to; x += (to - from) / 1000) {
      regressionChart.x.push(x);
      regressionChart.y.push(regression.predict(x));
    }

    return {
      widths: {
        x: xs,
        y: widths
      },
      fit: regressionChart,
      score: regression.score(xs, widths),
      // eslint-disable-next-line no-new-func
      predictFct: regression.predict.bind(regression),
      tex: regression.toLaTeX(3),
      A: regression.A,
      B: regression.B,
      predictFctString: `${regression.A} * mass ** ${regression.B}`
    };
  }

  var peaksWidth_1 = peaksWidth;

  /**
   *
   * @param {array} bestPeaks
   * @param {object} [options={}]
   * @param {array} [options.mfColors={}]
   * @param {number} [options.numberDigits=5]
   * @param {number} [options.numberMFs=0]
   * @param {boolean} [options.showMF=false]
   * @param {array} [options.mfColors={}]
   * @param {number} [options.charge=1]
   * @param {number} [options.shift=0]
   * @param {object} [options.mfPrefs]
   * @param {number} [options.displayCharge=true]
   *
   */


  function getPeaksAnnotation(bestPeaks, options = {}) {
    const emdb = new src$3();
    options = Object.assign({
      limit: 5,
      precision: 100
    }, options);
    let {
      numberDigits = 5,
      shift = 0,
      showMF = false,
      numberMFs = 0,
      charge = 1,
      mfPrefs = {},
      displayCharge = true,
      mfColors = [{
        limit: 3,
        color: 'green'
      }, {
        limit: 20,
        color: 'lightgreen'
      }, {
        limit: 50,
        color: 'lightorange'
      }]
    } = options;
    if (showMF && !numberMFs) numberMFs = 1;
    let annotations = [];
    bestPeaks.sort((a, b) => a.close ? -1 : b.close ? 1 : 0);

    for (let peak of bestPeaks) {
      let annotation;

      if (peak.close) {
        annotation = {
          type: 'line',
          _highlight: peak._highlight,
          info: peak,
          position: [{
            y: peak.y,
            dy: '-5px',
            x: peak.x
          }, {
            y: peak.y,
            dy: '-15px',
            x: peak.x
          }]
        };
        annotations.push(annotation);
        annotation = {
          type: 'ellipse',
          _highlight: peak._highlight,
          info: peak,
          position: [{
            y: peak.y,
            dy: '-15px',
            x: peak.x
          }],
          props: {
            rx: '3px',
            ry: '3px',
            fillOpacity: 0.3
          }
        };
      } else {
        annotation = {
          type: 'line',
          _highlight: peak._highlight,
          position: [{
            y: peak.y,
            dy: '-5px',
            x: peak.x
          }, {
            y: peak.y,
            dy: '-25px',
            x: peak.x
          }],
          labels: [{
            text: (peak.x + shift).toFixed(numberDigits),
            color: 'red',
            position: {
              x: peak.x,
              y: peak.y,
              dy: '-17px',
              dx: '2px'
            }
          }]
        };

        if (displayCharge) {
          annotation.labels.push({
            text: `Z:${peak.charge}`,
            color: 'grey',
            position: {
              x: peak.x,
              y: peak.y,
              dy: '-4px',
              dx: '2px'
            }
          });
        }

        if (numberMFs) {
          // we have 2 cases. Either there is a shift and we deal with differences
          // otherwise it is absolute
          // if there is a shift we consider only a neutral loss and the parameter charge is important
          if (shift) {
            // neutral loss
            let currentMfPrefs = Object.assign({}, mfPrefs, {
              allowNeutral: true,
              ionizations: ''
            }); // we need to deal with the precision and increase it

            currentMfPrefs.precision = currentMfPrefs.precision / Math.max(Math.abs(peak.x + shift), 1) * peak.x;
            emdb.fromMonoisotopicMass(Math.abs((peak.x + shift) * charge), currentMfPrefs);
          } else {
            emdb.fromMonoisotopicMass(Math.abs(peak.x * charge), mfPrefs);
          }

          let mfs = emdb.get('monoisotopic');
          let numberOfMFS = Math.min(mfs.length, numberMFs);

          for (let i = 0; i < numberOfMFS; i++) {
            let mf = mfs[i];
            let ppm = shift ? mf.ms.ppm / shift * mfs[0].ms.em : mf.ms.ppm;
            annotation.labels.push({
              text: mf.mf,
              color: getColor$1(mfColors, Math.abs(ppm)),
              position: {
                x: peak.x,
                y: peak.y,
                dy: `${-13 * (numberOfMFS - i) - 17}px`,
                dx: '2px'
              }
            });
          }
        }
      }

      annotations.push(annotation);
    }

    return annotations;
  }

  function getColor$1(colors, value) {
    for (let color of colors) {
      if (value < color.limit) return color.color;
    }

    return 'lightgrey';
  }

  var getPeaksAnnotation_1 = getPeaksAnnotation;

  var jsgraph = {
    getPeaksAnnotation: getPeaksAnnotation_1
  };

  var require$$0$3 = /*@__PURE__*/getAugmentedNamespace(src$o);

  const {
    parseXY
  } = require$$0$3;

  function Spectrum$2(data = {
    x: [],
    y: []
  }) {
    if (typeof data !== 'object' || !Array.isArray(data.x) || !Array.isArray(data.y)) {
      throw new TypeError('Spectrum data must be an object with x:[], y:[]');
    }

    this.data = {
      x: data.x,
      y: data.y
    };
    Object.defineProperty(this.data, 'xOriginal', {
      enumerable: false,
      writable: true
    });
    this.cache = {};
  }

  Spectrum$2.fromText = function fromText(text) {
    const data = parseXY(text);
    return new Spectrum$2(data);
  };

  Spectrum$2.prototype.maxY = function maxY() {
    return lib$7(this.data.y);
  };

  Spectrum$2.prototype.sumY = function sumY() {
    if (!this.cache.sumY) {
      this.cache.sumY = this.data.y.reduce((previous, current) => previous + current, 0);
    }

    return this.cache.sumY;
  };

  Spectrum$2.prototype.scaleY = function scaleY(intensity = 1) {
    let basePeak = this.maxY() / intensity;
    this.data.y = this.data.y.map(y => y / basePeak);
    return this;
  };

  Spectrum$2.prototype.rescaleX = function rescaleX(callback) {
    this.ensureOriginalX();

    for (let i = 0; i < this.data.x.length; i++) {
      this.data.x[i] = callback(this.data.xOriginal[i]);
    }

    return this;
  };

  Spectrum$2.prototype.ensureOriginalX = function ensureOriginalX() {
    if (!this.data.xOriginal) {
      this.data.xOriginal = this.data.x.slice(0);
    }
  };

  Spectrum$2.prototype.normedY = function normedY(total = 1) {
    this.data.y = lib$6(this.data.y);

    if (total !== 1) {
      this.data.y = this.data.y.map(y => y * total);
    }

    return this;
  };

  Spectrum$2.prototype.peakPicking = function () {
    peakPicking_1(this);
    return this.peaks;
  };

  Spectrum$2.prototype.peaksWidth = function () {
    peakPicking_1(this);
    return peaksWidth_1(this.peaks);
  };

  Spectrum$2.prototype.getBestPeaks = function (options) {
    peakPicking_1(this);
    return getBestPeaks_1(this.peaks, options);
  };

  Spectrum$2.prototype.getPeakChargeBySimilarity = function (targetMass, options) {
    return getPeakChargeBySimilarity_1(this, targetMass, options);
  };

  Spectrum$2.prototype.getPeaks = function (options) {
    peakPicking_1(this);
    return getPeaks_1(this.peaks, options);
  };

  Spectrum$2.prototype.isContinuous = function () {
    return isContinuous_1(this);
  };

  Spectrum$2.JsGraph = Spectrum$2.prototype.JsGraph = jsgraph;
  var Spectrum_1 = Spectrum$2;

  var Spectrum$1 = Spectrum_1;
  var getPeaks = getPeaks_1;
  var getBestPeaks = getBestPeaks_1;
  var src$k = {
    Spectrum: Spectrum$1,
    getPeaks: getPeaks,
    getBestPeaks: getBestPeaks
  };

  /*!

  JSZip v3.6.0 - A JavaScript class for generating and reading zip files
  <http://stuartk.com/jszip>

  (c) 2009-2016 Stuart Knightley <stuart [at] stuartk.com>
  Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown.

  JSZip uses the library pako released under the MIT license :
  https://github.com/nodeca/pako/blob/master/LICENSE
  */
  var jszip = createCommonjsModule$1(function (module, exports) {
    (function (f) {
      {
        module.exports = f();
      }
    })(function () {
      return function e(t, n, r) {
        function s(o, u) {
          if (!n[o]) {
            if (!t[o]) {
              var a = typeof commonjsRequire == "function" && commonjsRequire;
              if (!u && a) return a(o, !0);
              if (i) return i(o, !0);
              var f = new Error("Cannot find module '" + o + "'");
              throw f.code = "MODULE_NOT_FOUND", f;
            }

            var l = n[o] = {
              exports: {}
            };
            t[o][0].call(l.exports, function (e) {
              var n = t[o][1][e];
              return s(n ? n : e);
            }, l, l.exports, e, t, n, r);
          }

          return n[o].exports;
        }

        var i = typeof commonjsRequire == "function" && commonjsRequire;

        for (var o = 0; o < r.length; o++) s(r[o]);

        return s;
      }({
        1: [function (require, module, exports) {
          (function (global) {
            /*!
            
            JSZip v3.5.0 - A JavaScript class for generating and reading zip files
            <http://stuartk.com/jszip>
            
            (c) 2009-2016 Stuart Knightley <stuart [at] stuartk.com>
            Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown.
            
            JSZip uses the library pako released under the MIT license :
            https://github.com/nodeca/pako/blob/master/LICENSE
            */
            !function (e) {
              if ("object" == typeof exports && "undefined" != typeof module) module.exports = e();else {
                ("undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : this).JSZip = e();
              }
            }(function () {
              return function s(a, o, u) {
                function h(r, e) {
                  if (!o[r]) {
                    if (!a[r]) {
                      var t = "function" == typeof require && require;
                      if (!e && t) return t(r, !0);
                      if (f) return f(r, !0);
                      var n = new Error("Cannot find module '" + r + "'");
                      throw n.code = "MODULE_NOT_FOUND", n;
                    }

                    var i = o[r] = {
                      exports: {}
                    };
                    a[r][0].call(i.exports, function (e) {
                      var t = a[r][1][e];
                      return h(t || e);
                    }, i, i.exports, s, a, o, u);
                  }

                  return o[r].exports;
                }

                for (var f = "function" == typeof require && require, e = 0; e < u.length; e++) h(u[e]);

                return h;
              }({
                1: [function (l, t, n) {
                  (function (r) {
                    !function (e) {
                      "object" == typeof n && void 0 !== t ? t.exports = e() : ("undefined" != typeof window ? window : void 0 !== r ? r : "undefined" != typeof self ? self : this).JSZip = e();
                    }(function () {
                      return function s(a, o, u) {
                        function h(t, e) {
                          if (!o[t]) {
                            if (!a[t]) {
                              var r = "function" == typeof l && l;
                              if (!e && r) return r(t, !0);
                              if (f) return f(t, !0);
                              var n = new Error("Cannot find module '" + t + "'");
                              throw n.code = "MODULE_NOT_FOUND", n;
                            }

                            var i = o[t] = {
                              exports: {}
                            };
                            a[t][0].call(i.exports, function (e) {
                              return h(a[t][1][e] || e);
                            }, i, i.exports, s, a, o, u);
                          }

                          return o[t].exports;
                        }

                        for (var f = "function" == typeof l && l, e = 0; e < u.length; e++) h(u[e]);

                        return h;
                      }({
                        1: [function (l, t, n) {
                          (function (r) {
                            !function (e) {
                              "object" == typeof n && void 0 !== t ? t.exports = e() : ("undefined" != typeof window ? window : void 0 !== r ? r : "undefined" != typeof self ? self : this).JSZip = e();
                            }(function () {
                              return function s(a, o, u) {
                                function h(t, e) {
                                  if (!o[t]) {
                                    if (!a[t]) {
                                      var r = "function" == typeof l && l;
                                      if (!e && r) return r(t, !0);
                                      if (f) return f(t, !0);
                                      var n = new Error("Cannot find module '" + t + "'");
                                      throw n.code = "MODULE_NOT_FOUND", n;
                                    }

                                    var i = o[t] = {
                                      exports: {}
                                    };
                                    a[t][0].call(i.exports, function (e) {
                                      return h(a[t][1][e] || e);
                                    }, i, i.exports, s, a, o, u);
                                  }

                                  return o[t].exports;
                                }

                                for (var f = "function" == typeof l && l, e = 0; e < u.length; e++) h(u[e]);

                                return h;
                              }({
                                1: [function (l, t, n) {
                                  (function (r) {
                                    !function (e) {
                                      "object" == typeof n && void 0 !== t ? t.exports = e() : ("undefined" != typeof window ? window : void 0 !== r ? r : "undefined" != typeof self ? self : this).JSZip = e();
                                    }(function () {
                                      return function s(a, o, u) {
                                        function h(t, e) {
                                          if (!o[t]) {
                                            if (!a[t]) {
                                              var r = "function" == typeof l && l;
                                              if (!e && r) return r(t, !0);
                                              if (f) return f(t, !0);
                                              var n = new Error("Cannot find module '" + t + "'");
                                              throw n.code = "MODULE_NOT_FOUND", n;
                                            }

                                            var i = o[t] = {
                                              exports: {}
                                            };
                                            a[t][0].call(i.exports, function (e) {
                                              return h(a[t][1][e] || e);
                                            }, i, i.exports, s, a, o, u);
                                          }

                                          return o[t].exports;
                                        }

                                        for (var f = "function" == typeof l && l, e = 0; e < u.length; e++) h(u[e]);

                                        return h;
                                      }({
                                        1: [function (l, t, n) {
                                          (function (r) {
                                            !function (e) {
                                              "object" == typeof n && void 0 !== t ? t.exports = e() : ("undefined" != typeof window ? window : void 0 !== r ? r : "undefined" != typeof self ? self : this).JSZip = e();
                                            }(function () {
                                              return function s(a, o, u) {
                                                function h(t, e) {
                                                  if (!o[t]) {
                                                    if (!a[t]) {
                                                      var r = "function" == typeof l && l;
                                                      if (!e && r) return r(t, !0);
                                                      if (f) return f(t, !0);
                                                      var n = new Error("Cannot find module '" + t + "'");
                                                      throw n.code = "MODULE_NOT_FOUND", n;
                                                    }

                                                    var i = o[t] = {
                                                      exports: {}
                                                    };
                                                    a[t][0].call(i.exports, function (e) {
                                                      return h(a[t][1][e] || e);
                                                    }, i, i.exports, s, a, o, u);
                                                  }

                                                  return o[t].exports;
                                                }

                                                for (var f = "function" == typeof l && l, e = 0; e < u.length; e++) h(u[e]);

                                                return h;
                                              }({
                                                1: [function (e, t, r) {

                                                  var c = e("./utils"),
                                                      l = e("./support"),
                                                      p = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
                                                  r.encode = function (e) {
                                                    for (var t, r, n, i, s, a, o, u = [], h = 0, f = e.length, l = f, d = "string" !== c.getTypeOf(e); h < e.length;) l = f - h, n = d ? (t = e[h++], r = h < f ? e[h++] : 0, h < f ? e[h++] : 0) : (t = e.charCodeAt(h++), r = h < f ? e.charCodeAt(h++) : 0, h < f ? e.charCodeAt(h++) : 0), i = t >> 2, s = (3 & t) << 4 | r >> 4, a = 1 < l ? (15 & r) << 2 | n >> 6 : 64, o = 2 < l ? 63 & n : 64, u.push(p.charAt(i) + p.charAt(s) + p.charAt(a) + p.charAt(o));

                                                    return u.join("");
                                                  }, r.decode = function (e) {
                                                    var t,
                                                        r,
                                                        n,
                                                        i,
                                                        s,
                                                        a,
                                                        o = 0,
                                                        u = 0;
                                                    if ("data:" === e.substr(0, "data:".length)) throw new Error("Invalid base64 input, it looks like a data url.");
                                                    var h,
                                                        f = 3 * (e = e.replace(/[^A-Za-z0-9\+\/\=]/g, "")).length / 4;
                                                    if (e.charAt(e.length - 1) === p.charAt(64) && f--, e.charAt(e.length - 2) === p.charAt(64) && f--, f % 1 != 0) throw new Error("Invalid base64 input, bad content length.");

                                                    for (h = l.uint8array ? new Uint8Array(0 | f) : new Array(0 | f); o < e.length;) t = p.indexOf(e.charAt(o++)) << 2 | (i = p.indexOf(e.charAt(o++))) >> 4, r = (15 & i) << 4 | (s = p.indexOf(e.charAt(o++))) >> 2, n = (3 & s) << 6 | (a = p.indexOf(e.charAt(o++))), h[u++] = t, 64 !== s && (h[u++] = r), 64 !== a && (h[u++] = n);

                                                    return h;
                                                  };
                                                }, {
                                                  "./support": 30,
                                                  "./utils": 32
                                                }],
                                                2: [function (e, t, r) {

                                                  var n = e("./external"),
                                                      i = e("./stream/DataWorker"),
                                                      s = e("./stream/Crc32Probe"),
                                                      a = e("./stream/DataLengthProbe");

                                                  function o(e, t, r, n, i) {
                                                    this.compressedSize = e, this.uncompressedSize = t, this.crc32 = r, this.compression = n, this.compressedContent = i;
                                                  }

                                                  o.prototype = {
                                                    getContentWorker: function () {
                                                      var e = new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),
                                                          t = this;
                                                      return e.on("end", function () {
                                                        if (this.streamInfo.data_length !== t.uncompressedSize) throw new Error("Bug : uncompressed data size mismatch");
                                                      }), e;
                                                    },
                                                    getCompressedWorker: function () {
                                                      return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize", this.compressedSize).withStreamInfo("uncompressedSize", this.uncompressedSize).withStreamInfo("crc32", this.crc32).withStreamInfo("compression", this.compression);
                                                    }
                                                  }, o.createWorkerFrom = function (e, t, r) {
                                                    return e.pipe(new s()).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression", t);
                                                  }, t.exports = o;
                                                }, {
                                                  "./external": 6,
                                                  "./stream/Crc32Probe": 25,
                                                  "./stream/DataLengthProbe": 26,
                                                  "./stream/DataWorker": 27
                                                }],
                                                3: [function (e, t, r) {

                                                  var n = e("./stream/GenericWorker");
                                                  r.STORE = {
                                                    magic: "\0\0",
                                                    compressWorker: function (e) {
                                                      return new n("STORE compression");
                                                    },
                                                    uncompressWorker: function () {
                                                      return new n("STORE decompression");
                                                    }
                                                  }, r.DEFLATE = e("./flate");
                                                }, {
                                                  "./flate": 7,
                                                  "./stream/GenericWorker": 28
                                                }],
                                                4: [function (e, t, r) {

                                                  var n = e("./utils"),
                                                      a = function () {
                                                    for (var e, t = [], r = 0; r < 256; r++) {
                                                      e = r;

                                                      for (var n = 0; n < 8; n++) e = 1 & e ? 3988292384 ^ e >>> 1 : e >>> 1;

                                                      t[r] = e;
                                                    }

                                                    return t;
                                                  }();

                                                  t.exports = function (e, t) {
                                                    return void 0 !== e && e.length ? "string" !== n.getTypeOf(e) ? function (e, t, r) {
                                                      var n = a,
                                                          i = 0 + r;
                                                      e ^= -1;

                                                      for (var s = 0; s < i; s++) e = e >>> 8 ^ n[255 & (e ^ t[s])];

                                                      return -1 ^ e;
                                                    }(0 | t, e, e.length) : function (e, t, r) {
                                                      var n = a,
                                                          i = 0 + r;
                                                      e ^= -1;

                                                      for (var s = 0; s < i; s++) e = e >>> 8 ^ n[255 & (e ^ t.charCodeAt(s))];

                                                      return -1 ^ e;
                                                    }(0 | t, e, e.length) : 0;
                                                  };
                                                }, {
                                                  "./utils": 32
                                                }],
                                                5: [function (e, t, r) {

                                                  r.base64 = !1, r.binary = !1, r.dir = !1, r.createFolders = !0, r.date = null, r.compression = null, r.compressionOptions = null, r.comment = null, r.unixPermissions = null, r.dosPermissions = null;
                                                }, {}],
                                                6: [function (e, t, r) {

                                                  var n;
                                                  n = "undefined" != typeof Promise ? Promise : e("lie"), t.exports = {
                                                    Promise: n
                                                  };
                                                }, {
                                                  lie: 37
                                                }],
                                                7: [function (e, t, r) {

                                                  var n = "undefined" != typeof Uint8Array && "undefined" != typeof Uint16Array && "undefined" != typeof Uint32Array,
                                                      i = e("pako"),
                                                      s = e("./utils"),
                                                      a = e("./stream/GenericWorker"),
                                                      o = n ? "uint8array" : "array";

                                                  function u(e, t) {
                                                    a.call(this, "FlateWorker/" + e), this._pako = null, this._pakoAction = e, this._pakoOptions = t, this.meta = {};
                                                  }

                                                  r.magic = "\b\0", s.inherits(u, a), u.prototype.processChunk = function (e) {
                                                    this.meta = e.meta, null === this._pako && this._createPako(), this._pako.push(s.transformTo(o, e.data), !1);
                                                  }, u.prototype.flush = function () {
                                                    a.prototype.flush.call(this), null === this._pako && this._createPako(), this._pako.push([], !0);
                                                  }, u.prototype.cleanUp = function () {
                                                    a.prototype.cleanUp.call(this), this._pako = null;
                                                  }, u.prototype._createPako = function () {
                                                    this._pako = new i[this._pakoAction]({
                                                      raw: !0,
                                                      level: this._pakoOptions.level || -1
                                                    });
                                                    var t = this;

                                                    this._pako.onData = function (e) {
                                                      t.push({
                                                        data: e,
                                                        meta: t.meta
                                                      });
                                                    };
                                                  }, r.compressWorker = function (e) {
                                                    return new u("Deflate", e);
                                                  }, r.uncompressWorker = function () {
                                                    return new u("Inflate", {});
                                                  };
                                                }, {
                                                  "./stream/GenericWorker": 28,
                                                  "./utils": 32,
                                                  pako: 38
                                                }],
                                                8: [function (e, t, r) {

                                                  function I(e, t) {
                                                    var r,
                                                        n = "";

                                                    for (r = 0; r < t; r++) n += String.fromCharCode(255 & e), e >>>= 8;

                                                    return n;
                                                  }

                                                  function i(e, t, r, n, i, s) {
                                                    var a,
                                                        o,
                                                        u = e.file,
                                                        h = e.compression,
                                                        f = s !== B.utf8encode,
                                                        l = O.transformTo("string", s(u.name)),
                                                        d = O.transformTo("string", B.utf8encode(u.name)),
                                                        c = u.comment,
                                                        p = O.transformTo("string", s(c)),
                                                        m = O.transformTo("string", B.utf8encode(c)),
                                                        _ = d.length !== u.name.length,
                                                        g = m.length !== c.length,
                                                        v = "",
                                                        b = "",
                                                        w = "",
                                                        y = u.dir,
                                                        k = u.date,
                                                        x = {
                                                      crc32: 0,
                                                      compressedSize: 0,
                                                      uncompressedSize: 0
                                                    };

                                                    t && !r || (x.crc32 = e.crc32, x.compressedSize = e.compressedSize, x.uncompressedSize = e.uncompressedSize);
                                                    var S = 0;
                                                    t && (S |= 8), f || !_ && !g || (S |= 2048);
                                                    var z,
                                                        C = 0,
                                                        E = 0;
                                                    y && (C |= 16), "UNIX" === i ? (E = 798, C |= ((z = u.unixPermissions) || (z = y ? 16893 : 33204), (65535 & z) << 16)) : (E = 20, C |= 63 & (u.dosPermissions || 0)), a = k.getUTCHours(), a <<= 6, a |= k.getUTCMinutes(), a <<= 5, a |= k.getUTCSeconds() / 2, o = k.getUTCFullYear() - 1980, o <<= 4, o |= k.getUTCMonth() + 1, o <<= 5, o |= k.getUTCDate(), _ && (v += "up" + I((b = I(1, 1) + I(R(l), 4) + d).length, 2) + b), g && (v += "uc" + I((w = I(1, 1) + I(R(p), 4) + m).length, 2) + w);
                                                    var A = "";
                                                    return A += "\n\0", A += I(S, 2), A += h.magic, A += I(a, 2), A += I(o, 2), A += I(x.crc32, 4), A += I(x.compressedSize, 4), A += I(x.uncompressedSize, 4), A += I(l.length, 2), A += I(v.length, 2), {
                                                      fileRecord: T.LOCAL_FILE_HEADER + A + l + v,
                                                      dirRecord: T.CENTRAL_FILE_HEADER + I(E, 2) + A + I(p.length, 2) + "\0\0\0\0" + I(C, 4) + I(n, 4) + l + v + p
                                                    };
                                                  }

                                                  var O = e("../utils"),
                                                      s = e("../stream/GenericWorker"),
                                                      B = e("../utf8"),
                                                      R = e("../crc32"),
                                                      T = e("../signature");

                                                  function n(e, t, r, n) {
                                                    s.call(this, "ZipFileWorker"), this.bytesWritten = 0, this.zipComment = t, this.zipPlatform = r, this.encodeFileName = n, this.streamFiles = e, this.accumulate = !1, this.contentBuffer = [], this.dirRecords = [], this.currentSourceOffset = 0, this.entriesCount = 0, this.currentFile = null, this._sources = [];
                                                  }

                                                  O.inherits(n, s), n.prototype.push = function (e) {
                                                    var t = e.meta.percent || 0,
                                                        r = this.entriesCount,
                                                        n = this._sources.length;
                                                    this.accumulate ? this.contentBuffer.push(e) : (this.bytesWritten += e.data.length, s.prototype.push.call(this, {
                                                      data: e.data,
                                                      meta: {
                                                        currentFile: this.currentFile,
                                                        percent: r ? (t + 100 * (r - n - 1)) / r : 100
                                                      }
                                                    }));
                                                  }, n.prototype.openedSource = function (e) {
                                                    this.currentSourceOffset = this.bytesWritten, this.currentFile = e.file.name;
                                                    var t = this.streamFiles && !e.file.dir;

                                                    if (t) {
                                                      var r = i(e, t, !1, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
                                                      this.push({
                                                        data: r.fileRecord,
                                                        meta: {
                                                          percent: 0
                                                        }
                                                      });
                                                    } else this.accumulate = !0;
                                                  }, n.prototype.closedSource = function (e) {
                                                    this.accumulate = !1;
                                                    var t,
                                                        r = this.streamFiles && !e.file.dir,
                                                        n = i(e, r, !0, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
                                                    if (this.dirRecords.push(n.dirRecord), r) this.push({
                                                      data: (t = e, T.DATA_DESCRIPTOR + I(t.crc32, 4) + I(t.compressedSize, 4) + I(t.uncompressedSize, 4)),
                                                      meta: {
                                                        percent: 100
                                                      }
                                                    });else for (this.push({
                                                      data: n.fileRecord,
                                                      meta: {
                                                        percent: 0
                                                      }
                                                    }); this.contentBuffer.length;) this.push(this.contentBuffer.shift());
                                                    this.currentFile = null;
                                                  }, n.prototype.flush = function () {
                                                    for (var e = this.bytesWritten, t = 0; t < this.dirRecords.length; t++) this.push({
                                                      data: this.dirRecords[t],
                                                      meta: {
                                                        percent: 100
                                                      }
                                                    });

                                                    var r,
                                                        n,
                                                        i,
                                                        s,
                                                        a,
                                                        o,
                                                        u = this.bytesWritten - e,
                                                        h = (r = this.dirRecords.length, n = u, i = e, s = this.zipComment, a = this.encodeFileName, o = O.transformTo("string", a(s)), T.CENTRAL_DIRECTORY_END + "\0\0\0\0" + I(r, 2) + I(r, 2) + I(n, 4) + I(i, 4) + I(o.length, 2) + o);
                                                    this.push({
                                                      data: h,
                                                      meta: {
                                                        percent: 100
                                                      }
                                                    });
                                                  }, n.prototype.prepareNextSource = function () {
                                                    this.previous = this._sources.shift(), this.openedSource(this.previous.streamInfo), this.isPaused ? this.previous.pause() : this.previous.resume();
                                                  }, n.prototype.registerPrevious = function (e) {
                                                    this._sources.push(e);

                                                    var t = this;
                                                    return e.on("data", function (e) {
                                                      t.processChunk(e);
                                                    }), e.on("end", function () {
                                                      t.closedSource(t.previous.streamInfo), t._sources.length ? t.prepareNextSource() : t.end();
                                                    }), e.on("error", function (e) {
                                                      t.error(e);
                                                    }), this;
                                                  }, n.prototype.resume = function () {
                                                    return !!s.prototype.resume.call(this) && (!this.previous && this._sources.length ? (this.prepareNextSource(), !0) : this.previous || this._sources.length || this.generatedError ? void 0 : (this.end(), !0));
                                                  }, n.prototype.error = function (e) {
                                                    var t = this._sources;
                                                    if (!s.prototype.error.call(this, e)) return !1;

                                                    for (var r = 0; r < t.length; r++) try {
                                                      t[r].error(e);
                                                    } catch (e) {}

                                                    return !0;
                                                  }, n.prototype.lock = function () {
                                                    s.prototype.lock.call(this);

                                                    for (var e = this._sources, t = 0; t < e.length; t++) e[t].lock();
                                                  }, t.exports = n;
                                                }, {
                                                  "../crc32": 4,
                                                  "../signature": 23,
                                                  "../stream/GenericWorker": 28,
                                                  "../utf8": 31,
                                                  "../utils": 32
                                                }],
                                                9: [function (e, t, r) {

                                                  var h = e("../compressions"),
                                                      n = e("./ZipFileWorker");

                                                  r.generateWorker = function (e, a, t) {
                                                    var o = new n(a.streamFiles, t, a.platform, a.encodeFileName),
                                                        u = 0;

                                                    try {
                                                      e.forEach(function (e, t) {
                                                        u++;

                                                        var r = function (e, t) {
                                                          var r = e || t,
                                                              n = h[r];
                                                          if (!n) throw new Error(r + " is not a valid compression method !");
                                                          return n;
                                                        }(t.options.compression, a.compression),
                                                            n = t.options.compressionOptions || a.compressionOptions || {},
                                                            i = t.dir,
                                                            s = t.date;

                                                        t._compressWorker(r, n).withStreamInfo("file", {
                                                          name: e,
                                                          dir: i,
                                                          date: s,
                                                          comment: t.comment || "",
                                                          unixPermissions: t.unixPermissions,
                                                          dosPermissions: t.dosPermissions
                                                        }).pipe(o);
                                                      }), o.entriesCount = u;
                                                    } catch (e) {
                                                      o.error(e);
                                                    }

                                                    return o;
                                                  };
                                                }, {
                                                  "../compressions": 3,
                                                  "./ZipFileWorker": 8
                                                }],
                                                10: [function (e, t, r) {

                                                  function n() {
                                                    if (!(this instanceof n)) return new n();
                                                    if (arguments.length) throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
                                                    this.files = {}, this.comment = null, this.root = "", this.clone = function () {
                                                      var e = new n();

                                                      for (var t in this) "function" != typeof this[t] && (e[t] = this[t]);

                                                      return e;
                                                    };
                                                  }

                                                  (n.prototype = e("./object")).loadAsync = e("./load"), n.support = e("./support"), n.defaults = e("./defaults"), n.version = "3.5.0", n.loadAsync = function (e, t) {
                                                    return new n().loadAsync(e, t);
                                                  }, n.external = e("./external"), t.exports = n;
                                                }, {
                                                  "./defaults": 5,
                                                  "./external": 6,
                                                  "./load": 11,
                                                  "./object": 15,
                                                  "./support": 30
                                                }],
                                                11: [function (e, t, r) {

                                                  var n = e("./utils"),
                                                      i = e("./external"),
                                                      o = e("./utf8"),
                                                      u = e("./zipEntries"),
                                                      s = e("./stream/Crc32Probe"),
                                                      h = e("./nodejsUtils");

                                                  function f(n) {
                                                    return new i.Promise(function (e, t) {
                                                      var r = n.decompressed.getContentWorker().pipe(new s());
                                                      r.on("error", function (e) {
                                                        t(e);
                                                      }).on("end", function () {
                                                        r.streamInfo.crc32 !== n.decompressed.crc32 ? t(new Error("Corrupted zip : CRC32 mismatch")) : e();
                                                      }).resume();
                                                    });
                                                  }

                                                  t.exports = function (e, s) {
                                                    var a = this;
                                                    return s = n.extend(s || {}, {
                                                      base64: !1,
                                                      checkCRC32: !1,
                                                      optimizedBinaryString: !1,
                                                      createFolders: !1,
                                                      decodeFileName: o.utf8decode
                                                    }), h.isNode && h.isStream(e) ? i.Promise.reject(new Error("JSZip can't accept a stream when loading a zip file.")) : n.prepareContent("the loaded zip file", e, !0, s.optimizedBinaryString, s.base64).then(function (e) {
                                                      var t = new u(s);
                                                      return t.load(e), t;
                                                    }).then(function (e) {
                                                      var t = [i.Promise.resolve(e)],
                                                          r = e.files;
                                                      if (s.checkCRC32) for (var n = 0; n < r.length; n++) t.push(f(r[n]));
                                                      return i.Promise.all(t);
                                                    }).then(function (e) {
                                                      for (var t = e.shift(), r = t.files, n = 0; n < r.length; n++) {
                                                        var i = r[n];
                                                        a.file(i.fileNameStr, i.decompressed, {
                                                          binary: !0,
                                                          optimizedBinaryString: !0,
                                                          date: i.date,
                                                          dir: i.dir,
                                                          comment: i.fileCommentStr.length ? i.fileCommentStr : null,
                                                          unixPermissions: i.unixPermissions,
                                                          dosPermissions: i.dosPermissions,
                                                          createFolders: s.createFolders
                                                        });
                                                      }

                                                      return t.zipComment.length && (a.comment = t.zipComment), a;
                                                    });
                                                  };
                                                }, {
                                                  "./external": 6,
                                                  "./nodejsUtils": 14,
                                                  "./stream/Crc32Probe": 25,
                                                  "./utf8": 31,
                                                  "./utils": 32,
                                                  "./zipEntries": 33
                                                }],
                                                12: [function (e, t, r) {

                                                  var n = e("../utils"),
                                                      i = e("../stream/GenericWorker");

                                                  function s(e, t) {
                                                    i.call(this, "Nodejs stream input adapter for " + e), this._upstreamEnded = !1, this._bindStream(t);
                                                  }

                                                  n.inherits(s, i), s.prototype._bindStream = function (e) {
                                                    var t = this;
                                                    (this._stream = e).pause(), e.on("data", function (e) {
                                                      t.push({
                                                        data: e,
                                                        meta: {
                                                          percent: 0
                                                        }
                                                      });
                                                    }).on("error", function (e) {
                                                      t.isPaused ? this.generatedError = e : t.error(e);
                                                    }).on("end", function () {
                                                      t.isPaused ? t._upstreamEnded = !0 : t.end();
                                                    });
                                                  }, s.prototype.pause = function () {
                                                    return !!i.prototype.pause.call(this) && (this._stream.pause(), !0);
                                                  }, s.prototype.resume = function () {
                                                    return !!i.prototype.resume.call(this) && (this._upstreamEnded ? this.end() : this._stream.resume(), !0);
                                                  }, t.exports = s;
                                                }, {
                                                  "../stream/GenericWorker": 28,
                                                  "../utils": 32
                                                }],
                                                13: [function (e, t, r) {

                                                  var i = e("readable-stream").Readable;

                                                  function n(e, t, r) {
                                                    i.call(this, t), this._helper = e;
                                                    var n = this;
                                                    e.on("data", function (e, t) {
                                                      n.push(e) || n._helper.pause(), r && r(t);
                                                    }).on("error", function (e) {
                                                      n.emit("error", e);
                                                    }).on("end", function () {
                                                      n.push(null);
                                                    });
                                                  }

                                                  e("../utils").inherits(n, i), n.prototype._read = function () {
                                                    this._helper.resume();
                                                  }, t.exports = n;
                                                }, {
                                                  "../utils": 32,
                                                  "readable-stream": 16
                                                }],
                                                14: [function (e, t, r) {

                                                  t.exports = {
                                                    isNode: "undefined" != typeof Buffer,
                                                    newBufferFrom: function (e, t) {
                                                      if (Buffer.from && Buffer.from !== Uint8Array.from) return Buffer.from(e, t);
                                                      if ("number" == typeof e) throw new Error('The "data" argument must not be a number');
                                                      return new Buffer(e, t);
                                                    },
                                                    allocBuffer: function (e) {
                                                      if (Buffer.alloc) return Buffer.alloc(e);
                                                      var t = new Buffer(e);
                                                      return t.fill(0), t;
                                                    },
                                                    isBuffer: function (e) {
                                                      return Buffer.isBuffer(e);
                                                    },
                                                    isStream: function (e) {
                                                      return e && "function" == typeof e.on && "function" == typeof e.pause && "function" == typeof e.resume;
                                                    }
                                                  };
                                                }, {}],
                                                15: [function (e, t, r) {

                                                  function s(e, t, r) {
                                                    var n,
                                                        i = f.getTypeOf(t),
                                                        s = f.extend(r || {}, d);
                                                    s.date = s.date || new Date(), null !== s.compression && (s.compression = s.compression.toUpperCase()), "string" == typeof s.unixPermissions && (s.unixPermissions = parseInt(s.unixPermissions, 8)), s.unixPermissions && 16384 & s.unixPermissions && (s.dir = !0), s.dosPermissions && 16 & s.dosPermissions && (s.dir = !0), s.dir && (e = h(e)), s.createFolders && (n = function (e) {
                                                      "/" === e.slice(-1) && (e = e.substring(0, e.length - 1));
                                                      var t = e.lastIndexOf("/");
                                                      return 0 < t ? e.substring(0, t) : "";
                                                    }(e)) && g.call(this, n, !0);
                                                    var a,
                                                        o = "string" === i && !1 === s.binary && !1 === s.base64;
                                                    r && void 0 !== r.binary || (s.binary = !o), (t instanceof c && 0 === t.uncompressedSize || s.dir || !t || 0 === t.length) && (s.base64 = !1, s.binary = !0, t = "", s.compression = "STORE", i = "string"), a = t instanceof c || t instanceof l ? t : m.isNode && m.isStream(t) ? new _(e, t) : f.prepareContent(e, t, s.binary, s.optimizedBinaryString, s.base64);
                                                    var u = new p(e, a, s);
                                                    this.files[e] = u;
                                                  }

                                                  function h(e) {
                                                    return "/" !== e.slice(-1) && (e += "/"), e;
                                                  }

                                                  var i = e("./utf8"),
                                                      f = e("./utils"),
                                                      l = e("./stream/GenericWorker"),
                                                      a = e("./stream/StreamHelper"),
                                                      d = e("./defaults"),
                                                      c = e("./compressedObject"),
                                                      p = e("./zipObject"),
                                                      o = e("./generate"),
                                                      m = e("./nodejsUtils"),
                                                      _ = e("./nodejs/NodejsStreamInputAdapter"),
                                                      g = function (e, t) {
                                                    return t = void 0 !== t ? t : d.createFolders, e = h(e), this.files[e] || s.call(this, e, null, {
                                                      dir: !0,
                                                      createFolders: t
                                                    }), this.files[e];
                                                  };

                                                  function u(e) {
                                                    return "[object RegExp]" === Object.prototype.toString.call(e);
                                                  }

                                                  var n = {
                                                    load: function () {
                                                      throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
                                                    },
                                                    forEach: function (e) {
                                                      var t, r, n;

                                                      for (t in this.files) this.files.hasOwnProperty(t) && (n = this.files[t], (r = t.slice(this.root.length, t.length)) && t.slice(0, this.root.length) === this.root && e(r, n));
                                                    },
                                                    filter: function (r) {
                                                      var n = [];
                                                      return this.forEach(function (e, t) {
                                                        r(e, t) && n.push(t);
                                                      }), n;
                                                    },
                                                    file: function (e, t, r) {
                                                      if (1 !== arguments.length) return e = this.root + e, s.call(this, e, t, r), this;

                                                      if (u(e)) {
                                                        var n = e;
                                                        return this.filter(function (e, t) {
                                                          return !t.dir && n.test(e);
                                                        });
                                                      }

                                                      var i = this.files[this.root + e];
                                                      return i && !i.dir ? i : null;
                                                    },
                                                    folder: function (r) {
                                                      if (!r) return this;
                                                      if (u(r)) return this.filter(function (e, t) {
                                                        return t.dir && r.test(e);
                                                      });
                                                      var e = this.root + r,
                                                          t = g.call(this, e),
                                                          n = this.clone();
                                                      return n.root = t.name, n;
                                                    },
                                                    remove: function (r) {
                                                      r = this.root + r;
                                                      var e = this.files[r];
                                                      if (e || ("/" !== r.slice(-1) && (r += "/"), e = this.files[r]), e && !e.dir) delete this.files[r];else for (var t = this.filter(function (e, t) {
                                                        return t.name.slice(0, r.length) === r;
                                                      }), n = 0; n < t.length; n++) delete this.files[t[n].name];
                                                      return this;
                                                    },
                                                    generate: function (e) {
                                                      throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
                                                    },
                                                    generateInternalStream: function (e) {
                                                      var t,
                                                          r = {};

                                                      try {
                                                        if ((r = f.extend(e || {}, {
                                                          streamFiles: !1,
                                                          compression: "STORE",
                                                          compressionOptions: null,
                                                          type: "",
                                                          platform: "DOS",
                                                          comment: null,
                                                          mimeType: "application/zip",
                                                          encodeFileName: i.utf8encode
                                                        })).type = r.type.toLowerCase(), r.compression = r.compression.toUpperCase(), "binarystring" === r.type && (r.type = "string"), !r.type) throw new Error("No output type specified.");
                                                        f.checkSupport(r.type), "darwin" !== r.platform && "freebsd" !== r.platform && "linux" !== r.platform && "sunos" !== r.platform || (r.platform = "UNIX"), "win32" === r.platform && (r.platform = "DOS");
                                                        var n = r.comment || this.comment || "";
                                                        t = o.generateWorker(this, r, n);
                                                      } catch (e) {
                                                        (t = new l("error")).error(e);
                                                      }

                                                      return new a(t, r.type || "string", r.mimeType);
                                                    },
                                                    generateAsync: function (e, t) {
                                                      return this.generateInternalStream(e).accumulate(t);
                                                    },
                                                    generateNodeStream: function (e, t) {
                                                      return (e = e || {}).type || (e.type = "nodebuffer"), this.generateInternalStream(e).toNodejsStream(t);
                                                    }
                                                  };
                                                  t.exports = n;
                                                }, {
                                                  "./compressedObject": 2,
                                                  "./defaults": 5,
                                                  "./generate": 9,
                                                  "./nodejs/NodejsStreamInputAdapter": 12,
                                                  "./nodejsUtils": 14,
                                                  "./stream/GenericWorker": 28,
                                                  "./stream/StreamHelper": 29,
                                                  "./utf8": 31,
                                                  "./utils": 32,
                                                  "./zipObject": 35
                                                }],
                                                16: [function (e, t, r) {
                                                  t.exports = e("stream");
                                                }, {
                                                  stream: void 0
                                                }],
                                                17: [function (e, t, r) {

                                                  var n = e("./DataReader");

                                                  function i(e) {
                                                    n.call(this, e);

                                                    for (var t = 0; t < this.data.length; t++) e[t] = 255 & e[t];
                                                  }

                                                  e("../utils").inherits(i, n), i.prototype.byteAt = function (e) {
                                                    return this.data[this.zero + e];
                                                  }, i.prototype.lastIndexOfSignature = function (e) {
                                                    for (var t = e.charCodeAt(0), r = e.charCodeAt(1), n = e.charCodeAt(2), i = e.charCodeAt(3), s = this.length - 4; 0 <= s; --s) if (this.data[s] === t && this.data[s + 1] === r && this.data[s + 2] === n && this.data[s + 3] === i) return s - this.zero;

                                                    return -1;
                                                  }, i.prototype.readAndCheckSignature = function (e) {
                                                    var t = e.charCodeAt(0),
                                                        r = e.charCodeAt(1),
                                                        n = e.charCodeAt(2),
                                                        i = e.charCodeAt(3),
                                                        s = this.readData(4);
                                                    return t === s[0] && r === s[1] && n === s[2] && i === s[3];
                                                  }, i.prototype.readData = function (e) {
                                                    if (this.checkOffset(e), 0 === e) return [];
                                                    var t = this.data.slice(this.zero + this.index, this.zero + this.index + e);
                                                    return this.index += e, t;
                                                  }, t.exports = i;
                                                }, {
                                                  "../utils": 32,
                                                  "./DataReader": 18
                                                }],
                                                18: [function (e, t, r) {

                                                  var n = e("../utils");

                                                  function i(e) {
                                                    this.data = e, this.length = e.length, this.index = 0, this.zero = 0;
                                                  }

                                                  i.prototype = {
                                                    checkOffset: function (e) {
                                                      this.checkIndex(this.index + e);
                                                    },
                                                    checkIndex: function (e) {
                                                      if (this.length < this.zero + e || e < 0) throw new Error("End of data reached (data length = " + this.length + ", asked index = " + e + "). Corrupted zip ?");
                                                    },
                                                    setIndex: function (e) {
                                                      this.checkIndex(e), this.index = e;
                                                    },
                                                    skip: function (e) {
                                                      this.setIndex(this.index + e);
                                                    },
                                                    byteAt: function (e) {},
                                                    readInt: function (e) {
                                                      var t,
                                                          r = 0;

                                                      for (this.checkOffset(e), t = this.index + e - 1; t >= this.index; t--) r = (r << 8) + this.byteAt(t);

                                                      return this.index += e, r;
                                                    },
                                                    readString: function (e) {
                                                      return n.transformTo("string", this.readData(e));
                                                    },
                                                    readData: function (e) {},
                                                    lastIndexOfSignature: function (e) {},
                                                    readAndCheckSignature: function (e) {},
                                                    readDate: function () {
                                                      var e = this.readInt(4);
                                                      return new Date(Date.UTC(1980 + (e >> 25 & 127), (e >> 21 & 15) - 1, e >> 16 & 31, e >> 11 & 31, e >> 5 & 63, (31 & e) << 1));
                                                    }
                                                  }, t.exports = i;
                                                }, {
                                                  "../utils": 32
                                                }],
                                                19: [function (e, t, r) {

                                                  var n = e("./Uint8ArrayReader");

                                                  function i(e) {
                                                    n.call(this, e);
                                                  }

                                                  e("../utils").inherits(i, n), i.prototype.readData = function (e) {
                                                    this.checkOffset(e);
                                                    var t = this.data.slice(this.zero + this.index, this.zero + this.index + e);
                                                    return this.index += e, t;
                                                  }, t.exports = i;
                                                }, {
                                                  "../utils": 32,
                                                  "./Uint8ArrayReader": 21
                                                }],
                                                20: [function (e, t, r) {

                                                  var n = e("./DataReader");

                                                  function i(e) {
                                                    n.call(this, e);
                                                  }

                                                  e("../utils").inherits(i, n), i.prototype.byteAt = function (e) {
                                                    return this.data.charCodeAt(this.zero + e);
                                                  }, i.prototype.lastIndexOfSignature = function (e) {
                                                    return this.data.lastIndexOf(e) - this.zero;
                                                  }, i.prototype.readAndCheckSignature = function (e) {
                                                    return e === this.readData(4);
                                                  }, i.prototype.readData = function (e) {
                                                    this.checkOffset(e);
                                                    var t = this.data.slice(this.zero + this.index, this.zero + this.index + e);
                                                    return this.index += e, t;
                                                  }, t.exports = i;
                                                }, {
                                                  "../utils": 32,
                                                  "./DataReader": 18
                                                }],
                                                21: [function (e, t, r) {

                                                  var n = e("./ArrayReader");

                                                  function i(e) {
                                                    n.call(this, e);
                                                  }

                                                  e("../utils").inherits(i, n), i.prototype.readData = function (e) {
                                                    if (this.checkOffset(e), 0 === e) return new Uint8Array(0);
                                                    var t = this.data.subarray(this.zero + this.index, this.zero + this.index + e);
                                                    return this.index += e, t;
                                                  }, t.exports = i;
                                                }, {
                                                  "../utils": 32,
                                                  "./ArrayReader": 17
                                                }],
                                                22: [function (e, t, r) {

                                                  var n = e("../utils"),
                                                      i = e("../support"),
                                                      s = e("./ArrayReader"),
                                                      a = e("./StringReader"),
                                                      o = e("./NodeBufferReader"),
                                                      u = e("./Uint8ArrayReader");

                                                  t.exports = function (e) {
                                                    var t = n.getTypeOf(e);
                                                    return n.checkSupport(t), "string" !== t || i.uint8array ? "nodebuffer" === t ? new o(e) : i.uint8array ? new u(n.transformTo("uint8array", e)) : new s(n.transformTo("array", e)) : new a(e);
                                                  };
                                                }, {
                                                  "../support": 30,
                                                  "../utils": 32,
                                                  "./ArrayReader": 17,
                                                  "./NodeBufferReader": 19,
                                                  "./StringReader": 20,
                                                  "./Uint8ArrayReader": 21
                                                }],
                                                23: [function (e, t, r) {

                                                  r.LOCAL_FILE_HEADER = "PK", r.CENTRAL_FILE_HEADER = "PK", r.CENTRAL_DIRECTORY_END = "PK", r.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK", r.ZIP64_CENTRAL_DIRECTORY_END = "PK", r.DATA_DESCRIPTOR = "PK\b";
                                                }, {}],
                                                24: [function (e, t, r) {

                                                  var n = e("./GenericWorker"),
                                                      i = e("../utils");

                                                  function s(e) {
                                                    n.call(this, "ConvertWorker to " + e), this.destType = e;
                                                  }

                                                  i.inherits(s, n), s.prototype.processChunk = function (e) {
                                                    this.push({
                                                      data: i.transformTo(this.destType, e.data),
                                                      meta: e.meta
                                                    });
                                                  }, t.exports = s;
                                                }, {
                                                  "../utils": 32,
                                                  "./GenericWorker": 28
                                                }],
                                                25: [function (e, t, r) {

                                                  var n = e("./GenericWorker"),
                                                      i = e("../crc32");

                                                  function s() {
                                                    n.call(this, "Crc32Probe"), this.withStreamInfo("crc32", 0);
                                                  }

                                                  e("../utils").inherits(s, n), s.prototype.processChunk = function (e) {
                                                    this.streamInfo.crc32 = i(e.data, this.streamInfo.crc32 || 0), this.push(e);
                                                  }, t.exports = s;
                                                }, {
                                                  "../crc32": 4,
                                                  "../utils": 32,
                                                  "./GenericWorker": 28
                                                }],
                                                26: [function (e, t, r) {

                                                  var n = e("../utils"),
                                                      i = e("./GenericWorker");

                                                  function s(e) {
                                                    i.call(this, "DataLengthProbe for " + e), this.propName = e, this.withStreamInfo(e, 0);
                                                  }

                                                  n.inherits(s, i), s.prototype.processChunk = function (e) {
                                                    if (e) {
                                                      var t = this.streamInfo[this.propName] || 0;
                                                      this.streamInfo[this.propName] = t + e.data.length;
                                                    }

                                                    i.prototype.processChunk.call(this, e);
                                                  }, t.exports = s;
                                                }, {
                                                  "../utils": 32,
                                                  "./GenericWorker": 28
                                                }],
                                                27: [function (e, t, r) {

                                                  var n = e("../utils"),
                                                      i = e("./GenericWorker");

                                                  function s(e) {
                                                    i.call(this, "DataWorker");
                                                    var t = this;
                                                    this.dataIsReady = !1, this.index = 0, this.max = 0, this.data = null, this.type = "", this._tickScheduled = !1, e.then(function (e) {
                                                      t.dataIsReady = !0, t.data = e, t.max = e && e.length || 0, t.type = n.getTypeOf(e), t.isPaused || t._tickAndRepeat();
                                                    }, function (e) {
                                                      t.error(e);
                                                    });
                                                  }

                                                  n.inherits(s, i), s.prototype.cleanUp = function () {
                                                    i.prototype.cleanUp.call(this), this.data = null;
                                                  }, s.prototype.resume = function () {
                                                    return !!i.prototype.resume.call(this) && (!this._tickScheduled && this.dataIsReady && (this._tickScheduled = !0, n.delay(this._tickAndRepeat, [], this)), !0);
                                                  }, s.prototype._tickAndRepeat = function () {
                                                    this._tickScheduled = !1, this.isPaused || this.isFinished || (this._tick(), this.isFinished || (n.delay(this._tickAndRepeat, [], this), this._tickScheduled = !0));
                                                  }, s.prototype._tick = function () {
                                                    if (this.isPaused || this.isFinished) return !1;
                                                    var e = null,
                                                        t = Math.min(this.max, this.index + 16384);
                                                    if (this.index >= this.max) return this.end();

                                                    switch (this.type) {
                                                      case "string":
                                                        e = this.data.substring(this.index, t);
                                                        break;

                                                      case "uint8array":
                                                        e = this.data.subarray(this.index, t);
                                                        break;

                                                      case "array":
                                                      case "nodebuffer":
                                                        e = this.data.slice(this.index, t);
                                                    }

                                                    return this.index = t, this.push({
                                                      data: e,
                                                      meta: {
                                                        percent: this.max ? this.index / this.max * 100 : 0
                                                      }
                                                    });
                                                  }, t.exports = s;
                                                }, {
                                                  "../utils": 32,
                                                  "./GenericWorker": 28
                                                }],
                                                28: [function (e, t, r) {

                                                  function n(e) {
                                                    this.name = e || "default", this.streamInfo = {}, this.generatedError = null, this.extraStreamInfo = {}, this.isPaused = !0, this.isFinished = !1, this.isLocked = !1, this._listeners = {
                                                      data: [],
                                                      end: [],
                                                      error: []
                                                    }, this.previous = null;
                                                  }

                                                  n.prototype = {
                                                    push: function (e) {
                                                      this.emit("data", e);
                                                    },
                                                    end: function () {
                                                      if (this.isFinished) return !1;
                                                      this.flush();

                                                      try {
                                                        this.emit("end"), this.cleanUp(), this.isFinished = !0;
                                                      } catch (e) {
                                                        this.emit("error", e);
                                                      }

                                                      return !0;
                                                    },
                                                    error: function (e) {
                                                      return !this.isFinished && (this.isPaused ? this.generatedError = e : (this.isFinished = !0, this.emit("error", e), this.previous && this.previous.error(e), this.cleanUp()), !0);
                                                    },
                                                    on: function (e, t) {
                                                      return this._listeners[e].push(t), this;
                                                    },
                                                    cleanUp: function () {
                                                      this.streamInfo = this.generatedError = this.extraStreamInfo = null, this._listeners = [];
                                                    },
                                                    emit: function (e, t) {
                                                      if (this._listeners[e]) for (var r = 0; r < this._listeners[e].length; r++) this._listeners[e][r].call(this, t);
                                                    },
                                                    pipe: function (e) {
                                                      return e.registerPrevious(this);
                                                    },
                                                    registerPrevious: function (e) {
                                                      if (this.isLocked) throw new Error("The stream '" + this + "' has already been used.");
                                                      this.streamInfo = e.streamInfo, this.mergeStreamInfo(), this.previous = e;
                                                      var t = this;
                                                      return e.on("data", function (e) {
                                                        t.processChunk(e);
                                                      }), e.on("end", function () {
                                                        t.end();
                                                      }), e.on("error", function (e) {
                                                        t.error(e);
                                                      }), this;
                                                    },
                                                    pause: function () {
                                                      return !this.isPaused && !this.isFinished && (this.isPaused = !0, this.previous && this.previous.pause(), !0);
                                                    },
                                                    resume: function () {
                                                      if (!this.isPaused || this.isFinished) return !1;
                                                      var e = this.isPaused = !1;
                                                      return this.generatedError && (this.error(this.generatedError), e = !0), this.previous && this.previous.resume(), !e;
                                                    },
                                                    flush: function () {},
                                                    processChunk: function (e) {
                                                      this.push(e);
                                                    },
                                                    withStreamInfo: function (e, t) {
                                                      return this.extraStreamInfo[e] = t, this.mergeStreamInfo(), this;
                                                    },
                                                    mergeStreamInfo: function () {
                                                      for (var e in this.extraStreamInfo) this.extraStreamInfo.hasOwnProperty(e) && (this.streamInfo[e] = this.extraStreamInfo[e]);
                                                    },
                                                    lock: function () {
                                                      if (this.isLocked) throw new Error("The stream '" + this + "' has already been used.");
                                                      this.isLocked = !0, this.previous && this.previous.lock();
                                                    },
                                                    toString: function () {
                                                      var e = "Worker " + this.name;
                                                      return this.previous ? this.previous + " -> " + e : e;
                                                    }
                                                  }, t.exports = n;
                                                }, {}],
                                                29: [function (e, t, r) {

                                                  var h = e("../utils"),
                                                      i = e("./ConvertWorker"),
                                                      s = e("./GenericWorker"),
                                                      f = e("../base64"),
                                                      n = e("../support"),
                                                      a = e("../external"),
                                                      o = null;
                                                  if (n.nodestream) try {
                                                    o = e("../nodejs/NodejsStreamOutputAdapter");
                                                  } catch (e) {}

                                                  function u(e, t, r) {
                                                    var n = t;

                                                    switch (t) {
                                                      case "blob":
                                                      case "arraybuffer":
                                                        n = "uint8array";
                                                        break;

                                                      case "base64":
                                                        n = "string";
                                                    }

                                                    try {
                                                      this._internalType = n, this._outputType = t, this._mimeType = r, h.checkSupport(n), this._worker = e.pipe(new i(n)), e.lock();
                                                    } catch (e) {
                                                      this._worker = new s("error"), this._worker.error(e);
                                                    }
                                                  }

                                                  u.prototype = {
                                                    accumulate: function (e) {
                                                      return o = this, u = e, new a.Promise(function (t, r) {
                                                        var n = [],
                                                            i = o._internalType,
                                                            s = o._outputType,
                                                            a = o._mimeType;
                                                        o.on("data", function (e, t) {
                                                          n.push(e), u && u(t);
                                                        }).on("error", function (e) {
                                                          n = [], r(e);
                                                        }).on("end", function () {
                                                          try {
                                                            var e = function (e, t, r) {
                                                              switch (e) {
                                                                case "blob":
                                                                  return h.newBlob(h.transformTo("arraybuffer", t), r);

                                                                case "base64":
                                                                  return f.encode(t);

                                                                default:
                                                                  return h.transformTo(e, t);
                                                              }
                                                            }(s, function (e, t) {
                                                              var r,
                                                                  n = 0,
                                                                  i = null,
                                                                  s = 0;

                                                              for (r = 0; r < t.length; r++) s += t[r].length;

                                                              switch (e) {
                                                                case "string":
                                                                  return t.join("");

                                                                case "array":
                                                                  return Array.prototype.concat.apply([], t);

                                                                case "uint8array":
                                                                  for (i = new Uint8Array(s), r = 0; r < t.length; r++) i.set(t[r], n), n += t[r].length;

                                                                  return i;

                                                                case "nodebuffer":
                                                                  return Buffer.concat(t);

                                                                default:
                                                                  throw new Error("concat : unsupported type '" + e + "'");
                                                              }
                                                            }(i, n), a);

                                                            t(e);
                                                          } catch (e) {
                                                            r(e);
                                                          }

                                                          n = [];
                                                        }).resume();
                                                      });
                                                      var o, u;
                                                    },
                                                    on: function (e, t) {
                                                      var r = this;
                                                      return "data" === e ? this._worker.on(e, function (e) {
                                                        t.call(r, e.data, e.meta);
                                                      }) : this._worker.on(e, function () {
                                                        h.delay(t, arguments, r);
                                                      }), this;
                                                    },
                                                    resume: function () {
                                                      return h.delay(this._worker.resume, [], this._worker), this;
                                                    },
                                                    pause: function () {
                                                      return this._worker.pause(), this;
                                                    },
                                                    toNodejsStream: function (e) {
                                                      if (h.checkSupport("nodestream"), "nodebuffer" !== this._outputType) throw new Error(this._outputType + " is not supported by this method");
                                                      return new o(this, {
                                                        objectMode: "nodebuffer" !== this._outputType
                                                      }, e);
                                                    }
                                                  }, t.exports = u;
                                                }, {
                                                  "../base64": 1,
                                                  "../external": 6,
                                                  "../nodejs/NodejsStreamOutputAdapter": 13,
                                                  "../support": 30,
                                                  "../utils": 32,
                                                  "./ConvertWorker": 24,
                                                  "./GenericWorker": 28
                                                }],
                                                30: [function (e, t, r) {

                                                  if (r.base64 = !0, r.array = !0, r.string = !0, r.arraybuffer = "undefined" != typeof ArrayBuffer && "undefined" != typeof Uint8Array, r.nodebuffer = "undefined" != typeof Buffer, r.uint8array = "undefined" != typeof Uint8Array, "undefined" == typeof ArrayBuffer) r.blob = !1;else {
                                                    var n = new ArrayBuffer(0);

                                                    try {
                                                      r.blob = 0 === new Blob([n], {
                                                        type: "application/zip"
                                                      }).size;
                                                    } catch (e) {
                                                      try {
                                                        var i = new (self.BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder)();
                                                        i.append(n), r.blob = 0 === i.getBlob("application/zip").size;
                                                      } catch (e) {
                                                        r.blob = !1;
                                                      }
                                                    }
                                                  }

                                                  try {
                                                    r.nodestream = !!e("readable-stream").Readable;
                                                  } catch (e) {
                                                    r.nodestream = !1;
                                                  }
                                                }, {
                                                  "readable-stream": 16
                                                }],
                                                31: [function (e, t, s) {

                                                  for (var o = e("./utils"), u = e("./support"), r = e("./nodejsUtils"), n = e("./stream/GenericWorker"), h = new Array(256), i = 0; i < 256; i++) h[i] = 252 <= i ? 6 : 248 <= i ? 5 : 240 <= i ? 4 : 224 <= i ? 3 : 192 <= i ? 2 : 1;

                                                  function a() {
                                                    n.call(this, "utf-8 decode"), this.leftOver = null;
                                                  }

                                                  function f() {
                                                    n.call(this, "utf-8 encode");
                                                  }

                                                  h[254] = h[254] = 1, s.utf8encode = function (e) {
                                                    return u.nodebuffer ? r.newBufferFrom(e, "utf-8") : function (e) {
                                                      var t,
                                                          r,
                                                          n,
                                                          i,
                                                          s,
                                                          a = e.length,
                                                          o = 0;

                                                      for (i = 0; i < a; i++) 55296 == (64512 & (r = e.charCodeAt(i))) && i + 1 < a && 56320 == (64512 & (n = e.charCodeAt(i + 1))) && (r = 65536 + (r - 55296 << 10) + (n - 56320), i++), o += r < 128 ? 1 : r < 2048 ? 2 : r < 65536 ? 3 : 4;

                                                      for (t = u.uint8array ? new Uint8Array(o) : new Array(o), i = s = 0; s < o; i++) 55296 == (64512 & (r = e.charCodeAt(i))) && i + 1 < a && 56320 == (64512 & (n = e.charCodeAt(i + 1))) && (r = 65536 + (r - 55296 << 10) + (n - 56320), i++), r < 128 ? t[s++] = r : (r < 2048 ? t[s++] = 192 | r >>> 6 : (r < 65536 ? t[s++] = 224 | r >>> 12 : (t[s++] = 240 | r >>> 18, t[s++] = 128 | r >>> 12 & 63), t[s++] = 128 | r >>> 6 & 63), t[s++] = 128 | 63 & r);

                                                      return t;
                                                    }(e);
                                                  }, s.utf8decode = function (e) {
                                                    return u.nodebuffer ? o.transformTo("nodebuffer", e).toString("utf-8") : function (e) {
                                                      var t,
                                                          r,
                                                          n,
                                                          i,
                                                          s = e.length,
                                                          a = new Array(2 * s);

                                                      for (t = r = 0; t < s;) if ((n = e[t++]) < 128) a[r++] = n;else if (4 < (i = h[n])) a[r++] = 65533, t += i - 1;else {
                                                        for (n &= 2 === i ? 31 : 3 === i ? 15 : 7; 1 < i && t < s;) n = n << 6 | 63 & e[t++], i--;

                                                        1 < i ? a[r++] = 65533 : n < 65536 ? a[r++] = n : (n -= 65536, a[r++] = 55296 | n >> 10 & 1023, a[r++] = 56320 | 1023 & n);
                                                      }

                                                      return a.length !== r && (a.subarray ? a = a.subarray(0, r) : a.length = r), o.applyFromCharCode(a);
                                                    }(e = o.transformTo(u.uint8array ? "uint8array" : "array", e));
                                                  }, o.inherits(a, n), a.prototype.processChunk = function (e) {
                                                    var t = o.transformTo(u.uint8array ? "uint8array" : "array", e.data);

                                                    if (this.leftOver && this.leftOver.length) {
                                                      if (u.uint8array) {
                                                        var r = t;
                                                        (t = new Uint8Array(r.length + this.leftOver.length)).set(this.leftOver, 0), t.set(r, this.leftOver.length);
                                                      } else t = this.leftOver.concat(t);

                                                      this.leftOver = null;
                                                    }

                                                    var n = function (e, t) {
                                                      var r;

                                                      for ((t = t || e.length) > e.length && (t = e.length), r = t - 1; 0 <= r && 128 == (192 & e[r]);) r--;

                                                      return r < 0 ? t : 0 === r ? t : r + h[e[r]] > t ? r : t;
                                                    }(t),
                                                        i = t;

                                                    n !== t.length && (u.uint8array ? (i = t.subarray(0, n), this.leftOver = t.subarray(n, t.length)) : (i = t.slice(0, n), this.leftOver = t.slice(n, t.length))), this.push({
                                                      data: s.utf8decode(i),
                                                      meta: e.meta
                                                    });
                                                  }, a.prototype.flush = function () {
                                                    this.leftOver && this.leftOver.length && (this.push({
                                                      data: s.utf8decode(this.leftOver),
                                                      meta: {}
                                                    }), this.leftOver = null);
                                                  }, s.Utf8DecodeWorker = a, o.inherits(f, n), f.prototype.processChunk = function (e) {
                                                    this.push({
                                                      data: s.utf8encode(e.data),
                                                      meta: e.meta
                                                    });
                                                  }, s.Utf8EncodeWorker = f;
                                                }, {
                                                  "./nodejsUtils": 14,
                                                  "./stream/GenericWorker": 28,
                                                  "./support": 30,
                                                  "./utils": 32
                                                }],
                                                32: [function (e, t, o) {

                                                  var u = e("./support"),
                                                      h = e("./base64"),
                                                      r = e("./nodejsUtils"),
                                                      n = e("set-immediate-shim"),
                                                      f = e("./external");

                                                  function i(e) {
                                                    return e;
                                                  }

                                                  function l(e, t) {
                                                    for (var r = 0; r < e.length; ++r) t[r] = 255 & e.charCodeAt(r);

                                                    return t;
                                                  }

                                                  o.newBlob = function (t, r) {
                                                    o.checkSupport("blob");

                                                    try {
                                                      return new Blob([t], {
                                                        type: r
                                                      });
                                                    } catch (e) {
                                                      try {
                                                        var n = new (self.BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder)();
                                                        return n.append(t), n.getBlob(r);
                                                      } catch (e) {
                                                        throw new Error("Bug : can't construct the Blob.");
                                                      }
                                                    }
                                                  };

                                                  var s = {
                                                    stringifyByChunk: function (e, t, r) {
                                                      var n = [],
                                                          i = 0,
                                                          s = e.length;
                                                      if (s <= r) return String.fromCharCode.apply(null, e);

                                                      for (; i < s;) "array" === t || "nodebuffer" === t ? n.push(String.fromCharCode.apply(null, e.slice(i, Math.min(i + r, s)))) : n.push(String.fromCharCode.apply(null, e.subarray(i, Math.min(i + r, s)))), i += r;

                                                      return n.join("");
                                                    },
                                                    stringifyByChar: function (e) {
                                                      for (var t = "", r = 0; r < e.length; r++) t += String.fromCharCode(e[r]);

                                                      return t;
                                                    },
                                                    applyCanBeUsed: {
                                                      uint8array: function () {
                                                        try {
                                                          return u.uint8array && 1 === String.fromCharCode.apply(null, new Uint8Array(1)).length;
                                                        } catch (e) {
                                                          return !1;
                                                        }
                                                      }(),
                                                      nodebuffer: function () {
                                                        try {
                                                          return u.nodebuffer && 1 === String.fromCharCode.apply(null, r.allocBuffer(1)).length;
                                                        } catch (e) {
                                                          return !1;
                                                        }
                                                      }()
                                                    }
                                                  };

                                                  function a(e) {
                                                    var t = 65536,
                                                        r = o.getTypeOf(e),
                                                        n = !0;
                                                    if ("uint8array" === r ? n = s.applyCanBeUsed.uint8array : "nodebuffer" === r && (n = s.applyCanBeUsed.nodebuffer), n) for (; 1 < t;) try {
                                                      return s.stringifyByChunk(e, r, t);
                                                    } catch (e) {
                                                      t = Math.floor(t / 2);
                                                    }
                                                    return s.stringifyByChar(e);
                                                  }

                                                  function d(e, t) {
                                                    for (var r = 0; r < e.length; r++) t[r] = e[r];

                                                    return t;
                                                  }

                                                  o.applyFromCharCode = a;
                                                  var c = {};
                                                  c.string = {
                                                    string: i,
                                                    array: function (e) {
                                                      return l(e, new Array(e.length));
                                                    },
                                                    arraybuffer: function (e) {
                                                      return c.string.uint8array(e).buffer;
                                                    },
                                                    uint8array: function (e) {
                                                      return l(e, new Uint8Array(e.length));
                                                    },
                                                    nodebuffer: function (e) {
                                                      return l(e, r.allocBuffer(e.length));
                                                    }
                                                  }, c.array = {
                                                    string: a,
                                                    array: i,
                                                    arraybuffer: function (e) {
                                                      return new Uint8Array(e).buffer;
                                                    },
                                                    uint8array: function (e) {
                                                      return new Uint8Array(e);
                                                    },
                                                    nodebuffer: function (e) {
                                                      return r.newBufferFrom(e);
                                                    }
                                                  }, c.arraybuffer = {
                                                    string: function (e) {
                                                      return a(new Uint8Array(e));
                                                    },
                                                    array: function (e) {
                                                      return d(new Uint8Array(e), new Array(e.byteLength));
                                                    },
                                                    arraybuffer: i,
                                                    uint8array: function (e) {
                                                      return new Uint8Array(e);
                                                    },
                                                    nodebuffer: function (e) {
                                                      return r.newBufferFrom(new Uint8Array(e));
                                                    }
                                                  }, c.uint8array = {
                                                    string: a,
                                                    array: function (e) {
                                                      return d(e, new Array(e.length));
                                                    },
                                                    arraybuffer: function (e) {
                                                      return e.buffer;
                                                    },
                                                    uint8array: i,
                                                    nodebuffer: function (e) {
                                                      return r.newBufferFrom(e);
                                                    }
                                                  }, c.nodebuffer = {
                                                    string: a,
                                                    array: function (e) {
                                                      return d(e, new Array(e.length));
                                                    },
                                                    arraybuffer: function (e) {
                                                      return c.nodebuffer.uint8array(e).buffer;
                                                    },
                                                    uint8array: function (e) {
                                                      return d(e, new Uint8Array(e.length));
                                                    },
                                                    nodebuffer: i
                                                  }, o.transformTo = function (e, t) {
                                                    if (t = t || "", !e) return t;
                                                    o.checkSupport(e);
                                                    var r = o.getTypeOf(t);
                                                    return c[r][e](t);
                                                  }, o.getTypeOf = function (e) {
                                                    return "string" == typeof e ? "string" : "[object Array]" === Object.prototype.toString.call(e) ? "array" : u.nodebuffer && r.isBuffer(e) ? "nodebuffer" : u.uint8array && e instanceof Uint8Array ? "uint8array" : u.arraybuffer && e instanceof ArrayBuffer ? "arraybuffer" : void 0;
                                                  }, o.checkSupport = function (e) {
                                                    if (!u[e.toLowerCase()]) throw new Error(e + " is not supported by this platform");
                                                  }, o.MAX_VALUE_16BITS = 65535, o.MAX_VALUE_32BITS = -1, o.pretty = function (e) {
                                                    var t,
                                                        r,
                                                        n = "";

                                                    for (r = 0; r < (e || "").length; r++) n += "\\x" + ((t = e.charCodeAt(r)) < 16 ? "0" : "") + t.toString(16).toUpperCase();

                                                    return n;
                                                  }, o.delay = function (e, t, r) {
                                                    n(function () {
                                                      e.apply(r || null, t || []);
                                                    });
                                                  }, o.inherits = function (e, t) {
                                                    function r() {}

                                                    r.prototype = t.prototype, e.prototype = new r();
                                                  }, o.extend = function () {
                                                    var e,
                                                        t,
                                                        r = {};

                                                    for (e = 0; e < arguments.length; e++) for (t in arguments[e]) arguments[e].hasOwnProperty(t) && void 0 === r[t] && (r[t] = arguments[e][t]);

                                                    return r;
                                                  }, o.prepareContent = function (n, e, i, s, a) {
                                                    return f.Promise.resolve(e).then(function (n) {
                                                      return u.blob && (n instanceof Blob || -1 !== ["[object File]", "[object Blob]"].indexOf(Object.prototype.toString.call(n))) && "undefined" != typeof FileReader ? new f.Promise(function (t, r) {
                                                        var e = new FileReader();
                                                        e.onload = function (e) {
                                                          t(e.target.result);
                                                        }, e.onerror = function (e) {
                                                          r(e.target.error);
                                                        }, e.readAsArrayBuffer(n);
                                                      }) : n;
                                                    }).then(function (e) {
                                                      var t,
                                                          r = o.getTypeOf(e);
                                                      return r ? ("arraybuffer" === r ? e = o.transformTo("uint8array", e) : "string" === r && (a ? e = h.decode(e) : i && !0 !== s && (e = l(t = e, u.uint8array ? new Uint8Array(t.length) : new Array(t.length)))), e) : f.Promise.reject(new Error("Can't read the data of '" + n + "'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?"));
                                                    });
                                                  };
                                                }, {
                                                  "./base64": 1,
                                                  "./external": 6,
                                                  "./nodejsUtils": 14,
                                                  "./support": 30,
                                                  "set-immediate-shim": 54
                                                }],
                                                33: [function (e, t, r) {

                                                  var n = e("./reader/readerFor"),
                                                      i = e("./utils"),
                                                      s = e("./signature"),
                                                      a = e("./zipEntry"),
                                                      o = (e("./utf8"), e("./support"));

                                                  function u(e) {
                                                    this.files = [], this.loadOptions = e;
                                                  }

                                                  u.prototype = {
                                                    checkSignature: function (e) {
                                                      if (!this.reader.readAndCheckSignature(e)) {
                                                        this.reader.index -= 4;
                                                        var t = this.reader.readString(4);
                                                        throw new Error("Corrupted zip or bug: unexpected signature (" + i.pretty(t) + ", expected " + i.pretty(e) + ")");
                                                      }
                                                    },
                                                    isSignature: function (e, t) {
                                                      var r = this.reader.index;
                                                      this.reader.setIndex(e);
                                                      var n = this.reader.readString(4) === t;
                                                      return this.reader.setIndex(r), n;
                                                    },
                                                    readBlockEndOfCentral: function () {
                                                      this.diskNumber = this.reader.readInt(2), this.diskWithCentralDirStart = this.reader.readInt(2), this.centralDirRecordsOnThisDisk = this.reader.readInt(2), this.centralDirRecords = this.reader.readInt(2), this.centralDirSize = this.reader.readInt(4), this.centralDirOffset = this.reader.readInt(4), this.zipCommentLength = this.reader.readInt(2);
                                                      var e = this.reader.readData(this.zipCommentLength),
                                                          t = o.uint8array ? "uint8array" : "array",
                                                          r = i.transformTo(t, e);
                                                      this.zipComment = this.loadOptions.decodeFileName(r);
                                                    },
                                                    readBlockZip64EndOfCentral: function () {
                                                      this.zip64EndOfCentralSize = this.reader.readInt(8), this.reader.skip(4), this.diskNumber = this.reader.readInt(4), this.diskWithCentralDirStart = this.reader.readInt(4), this.centralDirRecordsOnThisDisk = this.reader.readInt(8), this.centralDirRecords = this.reader.readInt(8), this.centralDirSize = this.reader.readInt(8), this.centralDirOffset = this.reader.readInt(8), this.zip64ExtensibleData = {};

                                                      for (var e, t, r, n = this.zip64EndOfCentralSize - 44; 0 < n;) e = this.reader.readInt(2), t = this.reader.readInt(4), r = this.reader.readData(t), this.zip64ExtensibleData[e] = {
                                                        id: e,
                                                        length: t,
                                                        value: r
                                                      };
                                                    },
                                                    readBlockZip64EndOfCentralLocator: function () {
                                                      if (this.diskWithZip64CentralDirStart = this.reader.readInt(4), this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8), this.disksCount = this.reader.readInt(4), 1 < this.disksCount) throw new Error("Multi-volumes zip are not supported");
                                                    },
                                                    readLocalFiles: function () {
                                                      var e, t;

                                                      for (e = 0; e < this.files.length; e++) t = this.files[e], this.reader.setIndex(t.localHeaderOffset), this.checkSignature(s.LOCAL_FILE_HEADER), t.readLocalPart(this.reader), t.handleUTF8(), t.processAttributes();
                                                    },
                                                    readCentralDir: function () {
                                                      var e;

                                                      for (this.reader.setIndex(this.centralDirOffset); this.reader.readAndCheckSignature(s.CENTRAL_FILE_HEADER);) (e = new a({
                                                        zip64: this.zip64
                                                      }, this.loadOptions)).readCentralPart(this.reader), this.files.push(e);

                                                      if (this.centralDirRecords !== this.files.length && 0 !== this.centralDirRecords && 0 === this.files.length) throw new Error("Corrupted zip or bug: expected " + this.centralDirRecords + " records in central dir, got " + this.files.length);
                                                    },
                                                    readEndOfCentral: function () {
                                                      var e = this.reader.lastIndexOfSignature(s.CENTRAL_DIRECTORY_END);
                                                      if (e < 0) throw this.isSignature(0, s.LOCAL_FILE_HEADER) ? new Error("Corrupted zip: can't find end of central directory") : new Error("Can't find end of central directory : is this a zip file ? If it is, see https://stuk.github.io/jszip/documentation/howto/read_zip.html");
                                                      this.reader.setIndex(e);
                                                      var t = e;

                                                      if (this.checkSignature(s.CENTRAL_DIRECTORY_END), this.readBlockEndOfCentral(), this.diskNumber === i.MAX_VALUE_16BITS || this.diskWithCentralDirStart === i.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === i.MAX_VALUE_16BITS || this.centralDirRecords === i.MAX_VALUE_16BITS || this.centralDirSize === i.MAX_VALUE_32BITS || this.centralDirOffset === i.MAX_VALUE_32BITS) {
                                                        if (this.zip64 = !0, (e = this.reader.lastIndexOfSignature(s.ZIP64_CENTRAL_DIRECTORY_LOCATOR)) < 0) throw new Error("Corrupted zip: can't find the ZIP64 end of central directory locator");
                                                        if (this.reader.setIndex(e), this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_LOCATOR), this.readBlockZip64EndOfCentralLocator(), !this.isSignature(this.relativeOffsetEndOfZip64CentralDir, s.ZIP64_CENTRAL_DIRECTORY_END) && (this.relativeOffsetEndOfZip64CentralDir = this.reader.lastIndexOfSignature(s.ZIP64_CENTRAL_DIRECTORY_END), this.relativeOffsetEndOfZip64CentralDir < 0)) throw new Error("Corrupted zip: can't find the ZIP64 end of central directory");
                                                        this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir), this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_END), this.readBlockZip64EndOfCentral();
                                                      }

                                                      var r = this.centralDirOffset + this.centralDirSize;
                                                      this.zip64 && (r += 20, r += 12 + this.zip64EndOfCentralSize);
                                                      var n = t - r;
                                                      if (0 < n) this.isSignature(t, s.CENTRAL_FILE_HEADER) || (this.reader.zero = n);else if (n < 0) throw new Error("Corrupted zip: missing " + Math.abs(n) + " bytes.");
                                                    },
                                                    prepareReader: function (e) {
                                                      this.reader = n(e);
                                                    },
                                                    load: function (e) {
                                                      this.prepareReader(e), this.readEndOfCentral(), this.readCentralDir(), this.readLocalFiles();
                                                    }
                                                  }, t.exports = u;
                                                }, {
                                                  "./reader/readerFor": 22,
                                                  "./signature": 23,
                                                  "./support": 30,
                                                  "./utf8": 31,
                                                  "./utils": 32,
                                                  "./zipEntry": 34
                                                }],
                                                34: [function (e, t, r) {

                                                  var n = e("./reader/readerFor"),
                                                      s = e("./utils"),
                                                      i = e("./compressedObject"),
                                                      a = e("./crc32"),
                                                      o = e("./utf8"),
                                                      u = e("./compressions"),
                                                      h = e("./support");

                                                  function f(e, t) {
                                                    this.options = e, this.loadOptions = t;
                                                  }

                                                  f.prototype = {
                                                    isEncrypted: function () {
                                                      return 1 == (1 & this.bitFlag);
                                                    },
                                                    useUTF8: function () {
                                                      return 2048 == (2048 & this.bitFlag);
                                                    },
                                                    readLocalPart: function (e) {
                                                      var t, r;
                                                      if (e.skip(22), this.fileNameLength = e.readInt(2), r = e.readInt(2), this.fileName = e.readData(this.fileNameLength), e.skip(r), -1 === this.compressedSize || -1 === this.uncompressedSize) throw new Error("Bug or corrupted zip : didn't get enough information from the central directory (compressedSize === -1 || uncompressedSize === -1)");
                                                      if (null === (t = function (e) {
                                                        for (var t in u) if (u.hasOwnProperty(t) && u[t].magic === e) return u[t];

                                                        return null;
                                                      }(this.compressionMethod))) throw new Error("Corrupted zip : compression " + s.pretty(this.compressionMethod) + " unknown (inner file : " + s.transformTo("string", this.fileName) + ")");
                                                      this.decompressed = new i(this.compressedSize, this.uncompressedSize, this.crc32, t, e.readData(this.compressedSize));
                                                    },
                                                    readCentralPart: function (e) {
                                                      this.versionMadeBy = e.readInt(2), e.skip(2), this.bitFlag = e.readInt(2), this.compressionMethod = e.readString(2), this.date = e.readDate(), this.crc32 = e.readInt(4), this.compressedSize = e.readInt(4), this.uncompressedSize = e.readInt(4);
                                                      var t = e.readInt(2);
                                                      if (this.extraFieldsLength = e.readInt(2), this.fileCommentLength = e.readInt(2), this.diskNumberStart = e.readInt(2), this.internalFileAttributes = e.readInt(2), this.externalFileAttributes = e.readInt(4), this.localHeaderOffset = e.readInt(4), this.isEncrypted()) throw new Error("Encrypted zip are not supported");
                                                      e.skip(t), this.readExtraFields(e), this.parseZIP64ExtraField(e), this.fileComment = e.readData(this.fileCommentLength);
                                                    },
                                                    processAttributes: function () {
                                                      this.unixPermissions = null, this.dosPermissions = null;
                                                      var e = this.versionMadeBy >> 8;
                                                      this.dir = !!(16 & this.externalFileAttributes), 0 == e && (this.dosPermissions = 63 & this.externalFileAttributes), 3 == e && (this.unixPermissions = this.externalFileAttributes >> 16 & 65535), this.dir || "/" !== this.fileNameStr.slice(-1) || (this.dir = !0);
                                                    },
                                                    parseZIP64ExtraField: function (e) {
                                                      if (this.extraFields[1]) {
                                                        var t = n(this.extraFields[1].value);
                                                        this.uncompressedSize === s.MAX_VALUE_32BITS && (this.uncompressedSize = t.readInt(8)), this.compressedSize === s.MAX_VALUE_32BITS && (this.compressedSize = t.readInt(8)), this.localHeaderOffset === s.MAX_VALUE_32BITS && (this.localHeaderOffset = t.readInt(8)), this.diskNumberStart === s.MAX_VALUE_32BITS && (this.diskNumberStart = t.readInt(4));
                                                      }
                                                    },
                                                    readExtraFields: function (e) {
                                                      var t,
                                                          r,
                                                          n,
                                                          i = e.index + this.extraFieldsLength;

                                                      for (this.extraFields || (this.extraFields = {}); e.index + 4 < i;) t = e.readInt(2), r = e.readInt(2), n = e.readData(r), this.extraFields[t] = {
                                                        id: t,
                                                        length: r,
                                                        value: n
                                                      };

                                                      e.setIndex(i);
                                                    },
                                                    handleUTF8: function () {
                                                      var e = h.uint8array ? "uint8array" : "array";
                                                      if (this.useUTF8()) this.fileNameStr = o.utf8decode(this.fileName), this.fileCommentStr = o.utf8decode(this.fileComment);else {
                                                        var t = this.findExtraFieldUnicodePath();
                                                        if (null !== t) this.fileNameStr = t;else {
                                                          var r = s.transformTo(e, this.fileName);
                                                          this.fileNameStr = this.loadOptions.decodeFileName(r);
                                                        }
                                                        var n = this.findExtraFieldUnicodeComment();
                                                        if (null !== n) this.fileCommentStr = n;else {
                                                          var i = s.transformTo(e, this.fileComment);
                                                          this.fileCommentStr = this.loadOptions.decodeFileName(i);
                                                        }
                                                      }
                                                    },
                                                    findExtraFieldUnicodePath: function () {
                                                      var e = this.extraFields[28789];

                                                      if (e) {
                                                        var t = n(e.value);
                                                        return 1 !== t.readInt(1) ? null : a(this.fileName) !== t.readInt(4) ? null : o.utf8decode(t.readData(e.length - 5));
                                                      }

                                                      return null;
                                                    },
                                                    findExtraFieldUnicodeComment: function () {
                                                      var e = this.extraFields[25461];

                                                      if (e) {
                                                        var t = n(e.value);
                                                        return 1 !== t.readInt(1) ? null : a(this.fileComment) !== t.readInt(4) ? null : o.utf8decode(t.readData(e.length - 5));
                                                      }

                                                      return null;
                                                    }
                                                  }, t.exports = f;
                                                }, {
                                                  "./compressedObject": 2,
                                                  "./compressions": 3,
                                                  "./crc32": 4,
                                                  "./reader/readerFor": 22,
                                                  "./support": 30,
                                                  "./utf8": 31,
                                                  "./utils": 32
                                                }],
                                                35: [function (e, t, r) {

                                                  function n(e, t, r) {
                                                    this.name = e, this.dir = r.dir, this.date = r.date, this.comment = r.comment, this.unixPermissions = r.unixPermissions, this.dosPermissions = r.dosPermissions, this._data = t, this._dataBinary = r.binary, this.options = {
                                                      compression: r.compression,
                                                      compressionOptions: r.compressionOptions
                                                    };
                                                  }

                                                  var s = e("./stream/StreamHelper"),
                                                      i = e("./stream/DataWorker"),
                                                      a = e("./utf8"),
                                                      o = e("./compressedObject"),
                                                      u = e("./stream/GenericWorker");
                                                  n.prototype = {
                                                    internalStream: function (e) {
                                                      var t = null,
                                                          r = "string";

                                                      try {
                                                        if (!e) throw new Error("No output type specified.");
                                                        var n = "string" === (r = e.toLowerCase()) || "text" === r;
                                                        "binarystring" !== r && "text" !== r || (r = "string"), t = this._decompressWorker();
                                                        var i = !this._dataBinary;
                                                        i && !n && (t = t.pipe(new a.Utf8EncodeWorker())), !i && n && (t = t.pipe(new a.Utf8DecodeWorker()));
                                                      } catch (e) {
                                                        (t = new u("error")).error(e);
                                                      }

                                                      return new s(t, r, "");
                                                    },
                                                    async: function (e, t) {
                                                      return this.internalStream(e).accumulate(t);
                                                    },
                                                    nodeStream: function (e, t) {
                                                      return this.internalStream(e || "nodebuffer").toNodejsStream(t);
                                                    },
                                                    _compressWorker: function (e, t) {
                                                      if (this._data instanceof o && this._data.compression.magic === e.magic) return this._data.getCompressedWorker();

                                                      var r = this._decompressWorker();

                                                      return this._dataBinary || (r = r.pipe(new a.Utf8EncodeWorker())), o.createWorkerFrom(r, e, t);
                                                    },
                                                    _decompressWorker: function () {
                                                      return this._data instanceof o ? this._data.getContentWorker() : this._data instanceof u ? this._data : new i(this._data);
                                                    }
                                                  };

                                                  for (var h = ["asText", "asBinary", "asNodeBuffer", "asUint8Array", "asArrayBuffer"], f = function () {
                                                    throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
                                                  }, l = 0; l < h.length; l++) n.prototype[h[l]] = f;

                                                  t.exports = n;
                                                }, {
                                                  "./compressedObject": 2,
                                                  "./stream/DataWorker": 27,
                                                  "./stream/GenericWorker": 28,
                                                  "./stream/StreamHelper": 29,
                                                  "./utf8": 31
                                                }],
                                                36: [function (e, f, t) {
                                                  (function (t) {

                                                    var r,
                                                        n,
                                                        e = t.MutationObserver || t.WebKitMutationObserver;

                                                    if (e) {
                                                      var i = 0,
                                                          s = new e(h),
                                                          a = t.document.createTextNode("");
                                                      s.observe(a, {
                                                        characterData: !0
                                                      }), r = function () {
                                                        a.data = i = ++i % 2;
                                                      };
                                                    } else if (t.setImmediate || void 0 === t.MessageChannel) r = "document" in t && "onreadystatechange" in t.document.createElement("script") ? function () {
                                                      var e = t.document.createElement("script");
                                                      e.onreadystatechange = function () {
                                                        h(), e.onreadystatechange = null, e.parentNode.removeChild(e), e = null;
                                                      }, t.document.documentElement.appendChild(e);
                                                    } : function () {
                                                      setTimeout(h, 0);
                                                    };else {
                                                      var o = new t.MessageChannel();
                                                      o.port1.onmessage = h, r = function () {
                                                        o.port2.postMessage(0);
                                                      };
                                                    }

                                                    var u = [];

                                                    function h() {
                                                      var e, t;
                                                      n = !0;

                                                      for (var r = u.length; r;) {
                                                        for (t = u, u = [], e = -1; ++e < r;) t[e]();

                                                        r = u.length;
                                                      }

                                                      n = !1;
                                                    }

                                                    f.exports = function (e) {
                                                      1 !== u.push(e) || n || r();
                                                    };
                                                  }).call(this, void 0 !== r ? r : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {});
                                                }, {}],
                                                37: [function (e, t, r) {

                                                  var i = e("immediate");

                                                  function h() {}

                                                  var f = {},
                                                      s = ["REJECTED"],
                                                      a = ["FULFILLED"],
                                                      n = ["PENDING"];

                                                  function o(e) {
                                                    if ("function" != typeof e) throw new TypeError("resolver must be a function");
                                                    this.state = n, this.queue = [], this.outcome = void 0, e !== h && c(this, e);
                                                  }

                                                  function u(e, t, r) {
                                                    this.promise = e, "function" == typeof t && (this.onFulfilled = t, this.callFulfilled = this.otherCallFulfilled), "function" == typeof r && (this.onRejected = r, this.callRejected = this.otherCallRejected);
                                                  }

                                                  function l(t, r, n) {
                                                    i(function () {
                                                      var e;

                                                      try {
                                                        e = r(n);
                                                      } catch (e) {
                                                        return f.reject(t, e);
                                                      }

                                                      e === t ? f.reject(t, new TypeError("Cannot resolve promise with itself")) : f.resolve(t, e);
                                                    });
                                                  }

                                                  function d(e) {
                                                    var t = e && e.then;
                                                    if (e && ("object" == typeof e || "function" == typeof e) && "function" == typeof t) return function () {
                                                      t.apply(e, arguments);
                                                    };
                                                  }

                                                  function c(t, e) {
                                                    var r = !1;

                                                    function n(e) {
                                                      r || (r = !0, f.reject(t, e));
                                                    }

                                                    function i(e) {
                                                      r || (r = !0, f.resolve(t, e));
                                                    }

                                                    var s = p(function () {
                                                      e(i, n);
                                                    });
                                                    "error" === s.status && n(s.value);
                                                  }

                                                  function p(e, t) {
                                                    var r = {};

                                                    try {
                                                      r.value = e(t), r.status = "success";
                                                    } catch (e) {
                                                      r.status = "error", r.value = e;
                                                    }

                                                    return r;
                                                  }

                                                  (t.exports = o).prototype.finally = function (t) {
                                                    if ("function" != typeof t) return this;
                                                    var r = this.constructor;
                                                    return this.then(function (e) {
                                                      return r.resolve(t()).then(function () {
                                                        return e;
                                                      });
                                                    }, function (e) {
                                                      return r.resolve(t()).then(function () {
                                                        throw e;
                                                      });
                                                    });
                                                  }, o.prototype.catch = function (e) {
                                                    return this.then(null, e);
                                                  }, o.prototype.then = function (e, t) {
                                                    if ("function" != typeof e && this.state === a || "function" != typeof t && this.state === s) return this;
                                                    var r = new this.constructor(h);
                                                    return this.state !== n ? l(r, this.state === a ? e : t, this.outcome) : this.queue.push(new u(r, e, t)), r;
                                                  }, u.prototype.callFulfilled = function (e) {
                                                    f.resolve(this.promise, e);
                                                  }, u.prototype.otherCallFulfilled = function (e) {
                                                    l(this.promise, this.onFulfilled, e);
                                                  }, u.prototype.callRejected = function (e) {
                                                    f.reject(this.promise, e);
                                                  }, u.prototype.otherCallRejected = function (e) {
                                                    l(this.promise, this.onRejected, e);
                                                  }, f.resolve = function (e, t) {
                                                    var r = p(d, t);
                                                    if ("error" === r.status) return f.reject(e, r.value);
                                                    var n = r.value;
                                                    if (n) c(e, n);else {
                                                      e.state = a, e.outcome = t;

                                                      for (var i = -1, s = e.queue.length; ++i < s;) e.queue[i].callFulfilled(t);
                                                    }
                                                    return e;
                                                  }, f.reject = function (e, t) {
                                                    e.state = s, e.outcome = t;

                                                    for (var r = -1, n = e.queue.length; ++r < n;) e.queue[r].callRejected(t);

                                                    return e;
                                                  }, o.resolve = function (e) {
                                                    return e instanceof this ? e : f.resolve(new this(h), e);
                                                  }, o.reject = function (e) {
                                                    var t = new this(h);
                                                    return f.reject(t, e);
                                                  }, o.all = function (e) {
                                                    var r = this;
                                                    if ("[object Array]" !== Object.prototype.toString.call(e)) return this.reject(new TypeError("must be an array"));
                                                    var n = e.length,
                                                        i = !1;
                                                    if (!n) return this.resolve([]);

                                                    for (var s = new Array(n), a = 0, t = -1, o = new this(h); ++t < n;) u(e[t], t);

                                                    return o;

                                                    function u(e, t) {
                                                      r.resolve(e).then(function (e) {
                                                        s[t] = e, ++a !== n || i || (i = !0, f.resolve(o, s));
                                                      }, function (e) {
                                                        i || (i = !0, f.reject(o, e));
                                                      });
                                                    }
                                                  }, o.race = function (e) {
                                                    if ("[object Array]" !== Object.prototype.toString.call(e)) return this.reject(new TypeError("must be an array"));
                                                    var t = e.length,
                                                        r = !1;
                                                    if (!t) return this.resolve([]);

                                                    for (var n, i = -1, s = new this(h); ++i < t;) n = e[i], this.resolve(n).then(function (e) {
                                                      r || (r = !0, f.resolve(s, e));
                                                    }, function (e) {
                                                      r || (r = !0, f.reject(s, e));
                                                    });

                                                    return s;
                                                  };
                                                }, {
                                                  immediate: 36
                                                }],
                                                38: [function (e, t, r) {

                                                  var n = {};
                                                  (0, e("./lib/utils/common").assign)(n, e("./lib/deflate"), e("./lib/inflate"), e("./lib/zlib/constants")), t.exports = n;
                                                }, {
                                                  "./lib/deflate": 39,
                                                  "./lib/inflate": 40,
                                                  "./lib/utils/common": 41,
                                                  "./lib/zlib/constants": 44
                                                }],
                                                39: [function (e, t, r) {

                                                  var a = e("./zlib/deflate"),
                                                      o = e("./utils/common"),
                                                      u = e("./utils/strings"),
                                                      i = e("./zlib/messages"),
                                                      s = e("./zlib/zstream"),
                                                      h = Object.prototype.toString,
                                                      f = 0,
                                                      l = -1,
                                                      d = 0,
                                                      c = 8;

                                                  function p(e) {
                                                    if (!(this instanceof p)) return new p(e);
                                                    this.options = o.assign({
                                                      level: l,
                                                      method: c,
                                                      chunkSize: 16384,
                                                      windowBits: 15,
                                                      memLevel: 8,
                                                      strategy: d,
                                                      to: ""
                                                    }, e || {});
                                                    var t = this.options;
                                                    t.raw && 0 < t.windowBits ? t.windowBits = -t.windowBits : t.gzip && 0 < t.windowBits && t.windowBits < 16 && (t.windowBits += 16), this.err = 0, this.msg = "", this.ended = !1, this.chunks = [], this.strm = new s(), this.strm.avail_out = 0;
                                                    var r = a.deflateInit2(this.strm, t.level, t.method, t.windowBits, t.memLevel, t.strategy);
                                                    if (r !== f) throw new Error(i[r]);

                                                    if (t.header && a.deflateSetHeader(this.strm, t.header), t.dictionary) {
                                                      var n;
                                                      if (n = "string" == typeof t.dictionary ? u.string2buf(t.dictionary) : "[object ArrayBuffer]" === h.call(t.dictionary) ? new Uint8Array(t.dictionary) : t.dictionary, (r = a.deflateSetDictionary(this.strm, n)) !== f) throw new Error(i[r]);
                                                      this._dict_set = !0;
                                                    }
                                                  }

                                                  function n(e, t) {
                                                    var r = new p(t);
                                                    if (r.push(e, !0), r.err) throw r.msg || i[r.err];
                                                    return r.result;
                                                  }

                                                  p.prototype.push = function (e, t) {
                                                    var r,
                                                        n,
                                                        i = this.strm,
                                                        s = this.options.chunkSize;
                                                    if (this.ended) return !1;
                                                    n = t === ~~t ? t : !0 === t ? 4 : 0, "string" == typeof e ? i.input = u.string2buf(e) : "[object ArrayBuffer]" === h.call(e) ? i.input = new Uint8Array(e) : i.input = e, i.next_in = 0, i.avail_in = i.input.length;

                                                    do {
                                                      if (0 === i.avail_out && (i.output = new o.Buf8(s), i.next_out = 0, i.avail_out = s), 1 !== (r = a.deflate(i, n)) && r !== f) return this.onEnd(r), !(this.ended = !0);
                                                      0 !== i.avail_out && (0 !== i.avail_in || 4 !== n && 2 !== n) || ("string" === this.options.to ? this.onData(u.buf2binstring(o.shrinkBuf(i.output, i.next_out))) : this.onData(o.shrinkBuf(i.output, i.next_out)));
                                                    } while ((0 < i.avail_in || 0 === i.avail_out) && 1 !== r);

                                                    return 4 === n ? (r = a.deflateEnd(this.strm), this.onEnd(r), this.ended = !0, r === f) : 2 !== n || (this.onEnd(f), !(i.avail_out = 0));
                                                  }, p.prototype.onData = function (e) {
                                                    this.chunks.push(e);
                                                  }, p.prototype.onEnd = function (e) {
                                                    e === f && ("string" === this.options.to ? this.result = this.chunks.join("") : this.result = o.flattenChunks(this.chunks)), this.chunks = [], this.err = e, this.msg = this.strm.msg;
                                                  }, r.Deflate = p, r.deflate = n, r.deflateRaw = function (e, t) {
                                                    return (t = t || {}).raw = !0, n(e, t);
                                                  }, r.gzip = function (e, t) {
                                                    return (t = t || {}).gzip = !0, n(e, t);
                                                  };
                                                }, {
                                                  "./utils/common": 41,
                                                  "./utils/strings": 42,
                                                  "./zlib/deflate": 46,
                                                  "./zlib/messages": 51,
                                                  "./zlib/zstream": 53
                                                }],
                                                40: [function (e, t, r) {

                                                  var d = e("./zlib/inflate"),
                                                      c = e("./utils/common"),
                                                      p = e("./utils/strings"),
                                                      m = e("./zlib/constants"),
                                                      n = e("./zlib/messages"),
                                                      i = e("./zlib/zstream"),
                                                      s = e("./zlib/gzheader"),
                                                      _ = Object.prototype.toString;

                                                  function a(e) {
                                                    if (!(this instanceof a)) return new a(e);
                                                    this.options = c.assign({
                                                      chunkSize: 16384,
                                                      windowBits: 0,
                                                      to: ""
                                                    }, e || {});
                                                    var t = this.options;
                                                    t.raw && 0 <= t.windowBits && t.windowBits < 16 && (t.windowBits = -t.windowBits, 0 === t.windowBits && (t.windowBits = -15)), !(0 <= t.windowBits && t.windowBits < 16) || e && e.windowBits || (t.windowBits += 32), 15 < t.windowBits && t.windowBits < 48 && 0 == (15 & t.windowBits) && (t.windowBits |= 15), this.err = 0, this.msg = "", this.ended = !1, this.chunks = [], this.strm = new i(), this.strm.avail_out = 0;
                                                    var r = d.inflateInit2(this.strm, t.windowBits);
                                                    if (r !== m.Z_OK) throw new Error(n[r]);
                                                    this.header = new s(), d.inflateGetHeader(this.strm, this.header);
                                                  }

                                                  function o(e, t) {
                                                    var r = new a(t);
                                                    if (r.push(e, !0), r.err) throw r.msg || n[r.err];
                                                    return r.result;
                                                  }

                                                  a.prototype.push = function (e, t) {
                                                    var r,
                                                        n,
                                                        i,
                                                        s,
                                                        a,
                                                        o,
                                                        u = this.strm,
                                                        h = this.options.chunkSize,
                                                        f = this.options.dictionary,
                                                        l = !1;
                                                    if (this.ended) return !1;
                                                    n = t === ~~t ? t : !0 === t ? m.Z_FINISH : m.Z_NO_FLUSH, "string" == typeof e ? u.input = p.binstring2buf(e) : "[object ArrayBuffer]" === _.call(e) ? u.input = new Uint8Array(e) : u.input = e, u.next_in = 0, u.avail_in = u.input.length;

                                                    do {
                                                      if (0 === u.avail_out && (u.output = new c.Buf8(h), u.next_out = 0, u.avail_out = h), (r = d.inflate(u, m.Z_NO_FLUSH)) === m.Z_NEED_DICT && f && (o = "string" == typeof f ? p.string2buf(f) : "[object ArrayBuffer]" === _.call(f) ? new Uint8Array(f) : f, r = d.inflateSetDictionary(this.strm, o)), r === m.Z_BUF_ERROR && !0 === l && (r = m.Z_OK, l = !1), r !== m.Z_STREAM_END && r !== m.Z_OK) return this.onEnd(r), !(this.ended = !0);
                                                      u.next_out && (0 !== u.avail_out && r !== m.Z_STREAM_END && (0 !== u.avail_in || n !== m.Z_FINISH && n !== m.Z_SYNC_FLUSH) || ("string" === this.options.to ? (i = p.utf8border(u.output, u.next_out), s = u.next_out - i, a = p.buf2string(u.output, i), u.next_out = s, u.avail_out = h - s, s && c.arraySet(u.output, u.output, i, s, 0), this.onData(a)) : this.onData(c.shrinkBuf(u.output, u.next_out)))), 0 === u.avail_in && 0 === u.avail_out && (l = !0);
                                                    } while ((0 < u.avail_in || 0 === u.avail_out) && r !== m.Z_STREAM_END);

                                                    return r === m.Z_STREAM_END && (n = m.Z_FINISH), n === m.Z_FINISH ? (r = d.inflateEnd(this.strm), this.onEnd(r), this.ended = !0, r === m.Z_OK) : n !== m.Z_SYNC_FLUSH || (this.onEnd(m.Z_OK), !(u.avail_out = 0));
                                                  }, a.prototype.onData = function (e) {
                                                    this.chunks.push(e);
                                                  }, a.prototype.onEnd = function (e) {
                                                    e === m.Z_OK && ("string" === this.options.to ? this.result = this.chunks.join("") : this.result = c.flattenChunks(this.chunks)), this.chunks = [], this.err = e, this.msg = this.strm.msg;
                                                  }, r.Inflate = a, r.inflate = o, r.inflateRaw = function (e, t) {
                                                    return (t = t || {}).raw = !0, o(e, t);
                                                  }, r.ungzip = o;
                                                }, {
                                                  "./utils/common": 41,
                                                  "./utils/strings": 42,
                                                  "./zlib/constants": 44,
                                                  "./zlib/gzheader": 47,
                                                  "./zlib/inflate": 49,
                                                  "./zlib/messages": 51,
                                                  "./zlib/zstream": 53
                                                }],
                                                41: [function (e, t, r) {

                                                  var n = "undefined" != typeof Uint8Array && "undefined" != typeof Uint16Array && "undefined" != typeof Int32Array;
                                                  r.assign = function (e) {
                                                    for (var t = Array.prototype.slice.call(arguments, 1); t.length;) {
                                                      var r = t.shift();

                                                      if (r) {
                                                        if ("object" != typeof r) throw new TypeError(r + "must be non-object");

                                                        for (var n in r) r.hasOwnProperty(n) && (e[n] = r[n]);
                                                      }
                                                    }

                                                    return e;
                                                  }, r.shrinkBuf = function (e, t) {
                                                    return e.length === t ? e : e.subarray ? e.subarray(0, t) : (e.length = t, e);
                                                  };
                                                  var i = {
                                                    arraySet: function (e, t, r, n, i) {
                                                      if (t.subarray && e.subarray) e.set(t.subarray(r, r + n), i);else for (var s = 0; s < n; s++) e[i + s] = t[r + s];
                                                    },
                                                    flattenChunks: function (e) {
                                                      var t, r, n, i, s, a;

                                                      for (t = n = 0, r = e.length; t < r; t++) n += e[t].length;

                                                      for (a = new Uint8Array(n), t = i = 0, r = e.length; t < r; t++) s = e[t], a.set(s, i), i += s.length;

                                                      return a;
                                                    }
                                                  },
                                                      s = {
                                                    arraySet: function (e, t, r, n, i) {
                                                      for (var s = 0; s < n; s++) e[i + s] = t[r + s];
                                                    },
                                                    flattenChunks: function (e) {
                                                      return [].concat.apply([], e);
                                                    }
                                                  };
                                                  r.setTyped = function (e) {
                                                    e ? (r.Buf8 = Uint8Array, r.Buf16 = Uint16Array, r.Buf32 = Int32Array, r.assign(r, i)) : (r.Buf8 = Array, r.Buf16 = Array, r.Buf32 = Array, r.assign(r, s));
                                                  }, r.setTyped(n);
                                                }, {}],
                                                42: [function (e, t, r) {

                                                  var u = e("./common"),
                                                      i = !0,
                                                      s = !0;

                                                  try {
                                                    String.fromCharCode.apply(null, [0]);
                                                  } catch (e) {
                                                    i = !1;
                                                  }

                                                  try {
                                                    String.fromCharCode.apply(null, new Uint8Array(1));
                                                  } catch (e) {
                                                    s = !1;
                                                  }

                                                  for (var h = new u.Buf8(256), n = 0; n < 256; n++) h[n] = 252 <= n ? 6 : 248 <= n ? 5 : 240 <= n ? 4 : 224 <= n ? 3 : 192 <= n ? 2 : 1;

                                                  function f(e, t) {
                                                    if (t < 65537 && (e.subarray && s || !e.subarray && i)) return String.fromCharCode.apply(null, u.shrinkBuf(e, t));

                                                    for (var r = "", n = 0; n < t; n++) r += String.fromCharCode(e[n]);

                                                    return r;
                                                  }

                                                  h[254] = h[254] = 1, r.string2buf = function (e) {
                                                    var t,
                                                        r,
                                                        n,
                                                        i,
                                                        s,
                                                        a = e.length,
                                                        o = 0;

                                                    for (i = 0; i < a; i++) 55296 == (64512 & (r = e.charCodeAt(i))) && i + 1 < a && 56320 == (64512 & (n = e.charCodeAt(i + 1))) && (r = 65536 + (r - 55296 << 10) + (n - 56320), i++), o += r < 128 ? 1 : r < 2048 ? 2 : r < 65536 ? 3 : 4;

                                                    for (t = new u.Buf8(o), i = s = 0; s < o; i++) 55296 == (64512 & (r = e.charCodeAt(i))) && i + 1 < a && 56320 == (64512 & (n = e.charCodeAt(i + 1))) && (r = 65536 + (r - 55296 << 10) + (n - 56320), i++), r < 128 ? t[s++] = r : (r < 2048 ? t[s++] = 192 | r >>> 6 : (r < 65536 ? t[s++] = 224 | r >>> 12 : (t[s++] = 240 | r >>> 18, t[s++] = 128 | r >>> 12 & 63), t[s++] = 128 | r >>> 6 & 63), t[s++] = 128 | 63 & r);

                                                    return t;
                                                  }, r.buf2binstring = function (e) {
                                                    return f(e, e.length);
                                                  }, r.binstring2buf = function (e) {
                                                    for (var t = new u.Buf8(e.length), r = 0, n = t.length; r < n; r++) t[r] = e.charCodeAt(r);

                                                    return t;
                                                  }, r.buf2string = function (e, t) {
                                                    var r,
                                                        n,
                                                        i,
                                                        s,
                                                        a = t || e.length,
                                                        o = new Array(2 * a);

                                                    for (r = n = 0; r < a;) if ((i = e[r++]) < 128) o[n++] = i;else if (4 < (s = h[i])) o[n++] = 65533, r += s - 1;else {
                                                      for (i &= 2 === s ? 31 : 3 === s ? 15 : 7; 1 < s && r < a;) i = i << 6 | 63 & e[r++], s--;

                                                      1 < s ? o[n++] = 65533 : i < 65536 ? o[n++] = i : (i -= 65536, o[n++] = 55296 | i >> 10 & 1023, o[n++] = 56320 | 1023 & i);
                                                    }

                                                    return f(o, n);
                                                  }, r.utf8border = function (e, t) {
                                                    var r;

                                                    for ((t = t || e.length) > e.length && (t = e.length), r = t - 1; 0 <= r && 128 == (192 & e[r]);) r--;

                                                    return r < 0 ? t : 0 === r ? t : r + h[e[r]] > t ? r : t;
                                                  };
                                                }, {
                                                  "./common": 41
                                                }],
                                                43: [function (e, t, r) {

                                                  t.exports = function (e, t, r, n) {
                                                    for (var i = 65535 & e | 0, s = e >>> 16 & 65535 | 0, a = 0; 0 !== r;) {
                                                      for (r -= a = 2e3 < r ? 2e3 : r; s = s + (i = i + t[n++] | 0) | 0, --a;);

                                                      i %= 65521, s %= 65521;
                                                    }

                                                    return i | s << 16 | 0;
                                                  };
                                                }, {}],
                                                44: [function (e, t, r) {

                                                  t.exports = {
                                                    Z_NO_FLUSH: 0,
                                                    Z_PARTIAL_FLUSH: 1,
                                                    Z_SYNC_FLUSH: 2,
                                                    Z_FULL_FLUSH: 3,
                                                    Z_FINISH: 4,
                                                    Z_BLOCK: 5,
                                                    Z_TREES: 6,
                                                    Z_OK: 0,
                                                    Z_STREAM_END: 1,
                                                    Z_NEED_DICT: 2,
                                                    Z_ERRNO: -1,
                                                    Z_STREAM_ERROR: -2,
                                                    Z_DATA_ERROR: -3,
                                                    Z_BUF_ERROR: -5,
                                                    Z_NO_COMPRESSION: 0,
                                                    Z_BEST_SPEED: 1,
                                                    Z_BEST_COMPRESSION: 9,
                                                    Z_DEFAULT_COMPRESSION: -1,
                                                    Z_FILTERED: 1,
                                                    Z_HUFFMAN_ONLY: 2,
                                                    Z_RLE: 3,
                                                    Z_FIXED: 4,
                                                    Z_DEFAULT_STRATEGY: 0,
                                                    Z_BINARY: 0,
                                                    Z_TEXT: 1,
                                                    Z_UNKNOWN: 2,
                                                    Z_DEFLATED: 8
                                                  };
                                                }, {}],
                                                45: [function (e, t, r) {

                                                  var o = function () {
                                                    for (var e, t = [], r = 0; r < 256; r++) {
                                                      e = r;

                                                      for (var n = 0; n < 8; n++) e = 1 & e ? 3988292384 ^ e >>> 1 : e >>> 1;

                                                      t[r] = e;
                                                    }

                                                    return t;
                                                  }();

                                                  t.exports = function (e, t, r, n) {
                                                    var i = o,
                                                        s = n + r;
                                                    e ^= -1;

                                                    for (var a = n; a < s; a++) e = e >>> 8 ^ i[255 & (e ^ t[a])];

                                                    return -1 ^ e;
                                                  };
                                                }, {}],
                                                46: [function (e, t, r) {

                                                  var u,
                                                      d = e("../utils/common"),
                                                      h = e("./trees"),
                                                      c = e("./adler32"),
                                                      p = e("./crc32"),
                                                      n = e("./messages"),
                                                      f = 0,
                                                      l = 0,
                                                      m = -2,
                                                      i = 2,
                                                      _ = 8,
                                                      s = 286,
                                                      a = 30,
                                                      o = 19,
                                                      g = 2 * s + 1,
                                                      v = 15,
                                                      b = 3,
                                                      w = 258,
                                                      y = w + b + 1,
                                                      k = 42,
                                                      x = 113;

                                                  function S(e, t) {
                                                    return e.msg = n[t], t;
                                                  }

                                                  function z(e) {
                                                    return (e << 1) - (4 < e ? 9 : 0);
                                                  }

                                                  function C(e) {
                                                    for (var t = e.length; 0 <= --t;) e[t] = 0;
                                                  }

                                                  function E(e) {
                                                    var t = e.state,
                                                        r = t.pending;
                                                    r > e.avail_out && (r = e.avail_out), 0 !== r && (d.arraySet(e.output, t.pending_buf, t.pending_out, r, e.next_out), e.next_out += r, t.pending_out += r, e.total_out += r, e.avail_out -= r, t.pending -= r, 0 === t.pending && (t.pending_out = 0));
                                                  }

                                                  function A(e, t) {
                                                    h._tr_flush_block(e, 0 <= e.block_start ? e.block_start : -1, e.strstart - e.block_start, t), e.block_start = e.strstart, E(e.strm);
                                                  }

                                                  function I(e, t) {
                                                    e.pending_buf[e.pending++] = t;
                                                  }

                                                  function O(e, t) {
                                                    e.pending_buf[e.pending++] = t >>> 8 & 255, e.pending_buf[e.pending++] = 255 & t;
                                                  }

                                                  function B(e, t) {
                                                    var r,
                                                        n,
                                                        i = e.max_chain_length,
                                                        s = e.strstart,
                                                        a = e.prev_length,
                                                        o = e.nice_match,
                                                        u = e.strstart > e.w_size - y ? e.strstart - (e.w_size - y) : 0,
                                                        h = e.window,
                                                        f = e.w_mask,
                                                        l = e.prev,
                                                        d = e.strstart + w,
                                                        c = h[s + a - 1],
                                                        p = h[s + a];
                                                    e.prev_length >= e.good_match && (i >>= 2), o > e.lookahead && (o = e.lookahead);

                                                    do {
                                                      if (h[(r = t) + a] === p && h[r + a - 1] === c && h[r] === h[s] && h[++r] === h[s + 1]) {
                                                        s += 2, r++;

                                                        do {} while (h[++s] === h[++r] && h[++s] === h[++r] && h[++s] === h[++r] && h[++s] === h[++r] && h[++s] === h[++r] && h[++s] === h[++r] && h[++s] === h[++r] && h[++s] === h[++r] && s < d);

                                                        if (n = w - (d - s), s = d - w, a < n) {
                                                          if (e.match_start = t, o <= (a = n)) break;
                                                          c = h[s + a - 1], p = h[s + a];
                                                        }
                                                      }
                                                    } while ((t = l[t & f]) > u && 0 != --i);

                                                    return a <= e.lookahead ? a : e.lookahead;
                                                  }

                                                  function R(e) {
                                                    var t,
                                                        r,
                                                        n,
                                                        i,
                                                        s,
                                                        a,
                                                        o,
                                                        u,
                                                        h,
                                                        f,
                                                        l = e.w_size;

                                                    do {
                                                      if (i = e.window_size - e.lookahead - e.strstart, e.strstart >= l + (l - y)) {
                                                        for (d.arraySet(e.window, e.window, l, l, 0), e.match_start -= l, e.strstart -= l, e.block_start -= l, t = r = e.hash_size; n = e.head[--t], e.head[t] = l <= n ? n - l : 0, --r;);

                                                        for (t = r = l; n = e.prev[--t], e.prev[t] = l <= n ? n - l : 0, --r;);

                                                        i += l;
                                                      }

                                                      if (0 === e.strm.avail_in) break;
                                                      if (a = e.strm, o = e.window, u = e.strstart + e.lookahead, f = void 0, (h = i) < (f = a.avail_in) && (f = h), r = 0 === f ? 0 : (a.avail_in -= f, d.arraySet(o, a.input, a.next_in, f, u), 1 === a.state.wrap ? a.adler = c(a.adler, o, f, u) : 2 === a.state.wrap && (a.adler = p(a.adler, o, f, u)), a.next_in += f, a.total_in += f, f), e.lookahead += r, e.lookahead + e.insert >= b) for (s = e.strstart - e.insert, e.ins_h = e.window[s], e.ins_h = (e.ins_h << e.hash_shift ^ e.window[s + 1]) & e.hash_mask; e.insert && (e.ins_h = (e.ins_h << e.hash_shift ^ e.window[s + b - 1]) & e.hash_mask, e.prev[s & e.w_mask] = e.head[e.ins_h], e.head[e.ins_h] = s, s++, e.insert--, !(e.lookahead + e.insert < b)););
                                                    } while (e.lookahead < y && 0 !== e.strm.avail_in);
                                                  }

                                                  function T(e, t) {
                                                    for (var r, n;;) {
                                                      if (e.lookahead < y) {
                                                        if (R(e), e.lookahead < y && t === f) return 1;
                                                        if (0 === e.lookahead) break;
                                                      }

                                                      if (r = 0, e.lookahead >= b && (e.ins_h = (e.ins_h << e.hash_shift ^ e.window[e.strstart + b - 1]) & e.hash_mask, r = e.prev[e.strstart & e.w_mask] = e.head[e.ins_h], e.head[e.ins_h] = e.strstart), 0 !== r && e.strstart - r <= e.w_size - y && (e.match_length = B(e, r)), e.match_length >= b) {
                                                        if (n = h._tr_tally(e, e.strstart - e.match_start, e.match_length - b), e.lookahead -= e.match_length, e.match_length <= e.max_lazy_match && e.lookahead >= b) {
                                                          for (e.match_length--; e.strstart++, e.ins_h = (e.ins_h << e.hash_shift ^ e.window[e.strstart + b - 1]) & e.hash_mask, r = e.prev[e.strstart & e.w_mask] = e.head[e.ins_h], e.head[e.ins_h] = e.strstart, 0 != --e.match_length;);

                                                          e.strstart++;
                                                        } else e.strstart += e.match_length, e.match_length = 0, e.ins_h = e.window[e.strstart], e.ins_h = (e.ins_h << e.hash_shift ^ e.window[e.strstart + 1]) & e.hash_mask;
                                                      } else n = h._tr_tally(e, 0, e.window[e.strstart]), e.lookahead--, e.strstart++;
                                                      if (n && (A(e, !1), 0 === e.strm.avail_out)) return 1;
                                                    }

                                                    return e.insert = e.strstart < b - 1 ? e.strstart : b - 1, 4 === t ? (A(e, !0), 0 === e.strm.avail_out ? 3 : 4) : e.last_lit && (A(e, !1), 0 === e.strm.avail_out) ? 1 : 2;
                                                  }

                                                  function D(e, t) {
                                                    for (var r, n, i;;) {
                                                      if (e.lookahead < y) {
                                                        if (R(e), e.lookahead < y && t === f) return 1;
                                                        if (0 === e.lookahead) break;
                                                      }

                                                      if (r = 0, e.lookahead >= b && (e.ins_h = (e.ins_h << e.hash_shift ^ e.window[e.strstart + b - 1]) & e.hash_mask, r = e.prev[e.strstart & e.w_mask] = e.head[e.ins_h], e.head[e.ins_h] = e.strstart), e.prev_length = e.match_length, e.prev_match = e.match_start, e.match_length = b - 1, 0 !== r && e.prev_length < e.max_lazy_match && e.strstart - r <= e.w_size - y && (e.match_length = B(e, r), e.match_length <= 5 && (1 === e.strategy || e.match_length === b && 4096 < e.strstart - e.match_start) && (e.match_length = b - 1)), e.prev_length >= b && e.match_length <= e.prev_length) {
                                                        for (i = e.strstart + e.lookahead - b, n = h._tr_tally(e, e.strstart - 1 - e.prev_match, e.prev_length - b), e.lookahead -= e.prev_length - 1, e.prev_length -= 2; ++e.strstart <= i && (e.ins_h = (e.ins_h << e.hash_shift ^ e.window[e.strstart + b - 1]) & e.hash_mask, r = e.prev[e.strstart & e.w_mask] = e.head[e.ins_h], e.head[e.ins_h] = e.strstart), 0 != --e.prev_length;);

                                                        if (e.match_available = 0, e.match_length = b - 1, e.strstart++, n && (A(e, !1), 0 === e.strm.avail_out)) return 1;
                                                      } else if (e.match_available) {
                                                        if ((n = h._tr_tally(e, 0, e.window[e.strstart - 1])) && A(e, !1), e.strstart++, e.lookahead--, 0 === e.strm.avail_out) return 1;
                                                      } else e.match_available = 1, e.strstart++, e.lookahead--;
                                                    }

                                                    return e.match_available && (n = h._tr_tally(e, 0, e.window[e.strstart - 1]), e.match_available = 0), e.insert = e.strstart < b - 1 ? e.strstart : b - 1, 4 === t ? (A(e, !0), 0 === e.strm.avail_out ? 3 : 4) : e.last_lit && (A(e, !1), 0 === e.strm.avail_out) ? 1 : 2;
                                                  }

                                                  function F(e, t, r, n, i) {
                                                    this.good_length = e, this.max_lazy = t, this.nice_length = r, this.max_chain = n, this.func = i;
                                                  }

                                                  function N() {
                                                    this.strm = null, this.status = 0, this.pending_buf = null, this.pending_buf_size = 0, this.pending_out = 0, this.pending = 0, this.wrap = 0, this.gzhead = null, this.gzindex = 0, this.method = _, this.last_flush = -1, this.w_size = 0, this.w_bits = 0, this.w_mask = 0, this.window = null, this.window_size = 0, this.prev = null, this.head = null, this.ins_h = 0, this.hash_size = 0, this.hash_bits = 0, this.hash_mask = 0, this.hash_shift = 0, this.block_start = 0, this.match_length = 0, this.prev_match = 0, this.match_available = 0, this.strstart = 0, this.match_start = 0, this.lookahead = 0, this.prev_length = 0, this.max_chain_length = 0, this.max_lazy_match = 0, this.level = 0, this.strategy = 0, this.good_match = 0, this.nice_match = 0, this.dyn_ltree = new d.Buf16(2 * g), this.dyn_dtree = new d.Buf16(2 * (2 * a + 1)), this.bl_tree = new d.Buf16(2 * (2 * o + 1)), C(this.dyn_ltree), C(this.dyn_dtree), C(this.bl_tree), this.l_desc = null, this.d_desc = null, this.bl_desc = null, this.bl_count = new d.Buf16(v + 1), this.heap = new d.Buf16(2 * s + 1), C(this.heap), this.heap_len = 0, this.heap_max = 0, this.depth = new d.Buf16(2 * s + 1), C(this.depth), this.l_buf = 0, this.lit_bufsize = 0, this.last_lit = 0, this.d_buf = 0, this.opt_len = 0, this.static_len = 0, this.matches = 0, this.insert = 0, this.bi_buf = 0, this.bi_valid = 0;
                                                  }

                                                  function U(e) {
                                                    var t;
                                                    return e && e.state ? (e.total_in = e.total_out = 0, e.data_type = i, (t = e.state).pending = 0, t.pending_out = 0, t.wrap < 0 && (t.wrap = -t.wrap), t.status = t.wrap ? k : x, e.adler = 2 === t.wrap ? 0 : 1, t.last_flush = f, h._tr_init(t), l) : S(e, m);
                                                  }

                                                  function P(e) {
                                                    var t,
                                                        r = U(e);
                                                    return r === l && ((t = e.state).window_size = 2 * t.w_size, C(t.head), t.max_lazy_match = u[t.level].max_lazy, t.good_match = u[t.level].good_length, t.nice_match = u[t.level].nice_length, t.max_chain_length = u[t.level].max_chain, t.strstart = 0, t.block_start = 0, t.lookahead = 0, t.insert = 0, t.match_length = t.prev_length = b - 1, t.match_available = 0, t.ins_h = 0), r;
                                                  }

                                                  function L(e, t, r, n, i, s) {
                                                    if (!e) return m;
                                                    var a = 1;
                                                    if (-1 === t && (t = 6), n < 0 ? (a = 0, n = -n) : 15 < n && (a = 2, n -= 16), i < 1 || 9 < i || r !== _ || n < 8 || 15 < n || t < 0 || 9 < t || s < 0 || 4 < s) return S(e, m);
                                                    8 === n && (n = 9);
                                                    var o = new N();
                                                    return (e.state = o).strm = e, o.wrap = a, o.gzhead = null, o.w_bits = n, o.w_size = 1 << o.w_bits, o.w_mask = o.w_size - 1, o.hash_bits = i + 7, o.hash_size = 1 << o.hash_bits, o.hash_mask = o.hash_size - 1, o.hash_shift = ~~((o.hash_bits + b - 1) / b), o.window = new d.Buf8(2 * o.w_size), o.head = new d.Buf16(o.hash_size), o.prev = new d.Buf16(o.w_size), o.lit_bufsize = 1 << i + 6, o.pending_buf_size = 4 * o.lit_bufsize, o.pending_buf = new d.Buf8(o.pending_buf_size), o.d_buf = 1 * o.lit_bufsize, o.l_buf = 3 * o.lit_bufsize, o.level = t, o.strategy = s, o.method = r, P(e);
                                                  }

                                                  u = [new F(0, 0, 0, 0, function (e, t) {
                                                    var r = 65535;

                                                    for (r > e.pending_buf_size - 5 && (r = e.pending_buf_size - 5);;) {
                                                      if (e.lookahead <= 1) {
                                                        if (R(e), 0 === e.lookahead && t === f) return 1;
                                                        if (0 === e.lookahead) break;
                                                      }

                                                      e.strstart += e.lookahead, e.lookahead = 0;
                                                      var n = e.block_start + r;
                                                      if ((0 === e.strstart || e.strstart >= n) && (e.lookahead = e.strstart - n, e.strstart = n, A(e, !1), 0 === e.strm.avail_out)) return 1;
                                                      if (e.strstart - e.block_start >= e.w_size - y && (A(e, !1), 0 === e.strm.avail_out)) return 1;
                                                    }

                                                    return e.insert = 0, 4 === t ? (A(e, !0), 0 === e.strm.avail_out ? 3 : 4) : (e.strstart > e.block_start && (A(e, !1), e.strm.avail_out), 1);
                                                  }), new F(4, 4, 8, 4, T), new F(4, 5, 16, 8, T), new F(4, 6, 32, 32, T), new F(4, 4, 16, 16, D), new F(8, 16, 32, 32, D), new F(8, 16, 128, 128, D), new F(8, 32, 128, 256, D), new F(32, 128, 258, 1024, D), new F(32, 258, 258, 4096, D)], r.deflateInit = function (e, t) {
                                                    return L(e, t, _, 15, 8, 0);
                                                  }, r.deflateInit2 = L, r.deflateReset = P, r.deflateResetKeep = U, r.deflateSetHeader = function (e, t) {
                                                    return e && e.state ? 2 !== e.state.wrap ? m : (e.state.gzhead = t, l) : m;
                                                  }, r.deflate = function (e, t) {
                                                    var r, n, i, s;
                                                    if (!e || !e.state || 5 < t || t < 0) return e ? S(e, m) : m;
                                                    if (n = e.state, !e.output || !e.input && 0 !== e.avail_in || 666 === n.status && 4 !== t) return S(e, 0 === e.avail_out ? -5 : m);
                                                    if (n.strm = e, r = n.last_flush, n.last_flush = t, n.status === k) if (2 === n.wrap) e.adler = 0, I(n, 31), I(n, 139), I(n, 8), n.gzhead ? (I(n, (n.gzhead.text ? 1 : 0) + (n.gzhead.hcrc ? 2 : 0) + (n.gzhead.extra ? 4 : 0) + (n.gzhead.name ? 8 : 0) + (n.gzhead.comment ? 16 : 0)), I(n, 255 & n.gzhead.time), I(n, n.gzhead.time >> 8 & 255), I(n, n.gzhead.time >> 16 & 255), I(n, n.gzhead.time >> 24 & 255), I(n, 9 === n.level ? 2 : 2 <= n.strategy || n.level < 2 ? 4 : 0), I(n, 255 & n.gzhead.os), n.gzhead.extra && n.gzhead.extra.length && (I(n, 255 & n.gzhead.extra.length), I(n, n.gzhead.extra.length >> 8 & 255)), n.gzhead.hcrc && (e.adler = p(e.adler, n.pending_buf, n.pending, 0)), n.gzindex = 0, n.status = 69) : (I(n, 0), I(n, 0), I(n, 0), I(n, 0), I(n, 0), I(n, 9 === n.level ? 2 : 2 <= n.strategy || n.level < 2 ? 4 : 0), I(n, 3), n.status = x);else {
                                                      var a = _ + (n.w_bits - 8 << 4) << 8;
                                                      a |= (2 <= n.strategy || n.level < 2 ? 0 : n.level < 6 ? 1 : 6 === n.level ? 2 : 3) << 6, 0 !== n.strstart && (a |= 32), a += 31 - a % 31, n.status = x, O(n, a), 0 !== n.strstart && (O(n, e.adler >>> 16), O(n, 65535 & e.adler)), e.adler = 1;
                                                    }
                                                    if (69 === n.status) if (n.gzhead.extra) {
                                                      for (i = n.pending; n.gzindex < (65535 & n.gzhead.extra.length) && (n.pending !== n.pending_buf_size || (n.gzhead.hcrc && n.pending > i && (e.adler = p(e.adler, n.pending_buf, n.pending - i, i)), E(e), i = n.pending, n.pending !== n.pending_buf_size));) I(n, 255 & n.gzhead.extra[n.gzindex]), n.gzindex++;

                                                      n.gzhead.hcrc && n.pending > i && (e.adler = p(e.adler, n.pending_buf, n.pending - i, i)), n.gzindex === n.gzhead.extra.length && (n.gzindex = 0, n.status = 73);
                                                    } else n.status = 73;
                                                    if (73 === n.status) if (n.gzhead.name) {
                                                      i = n.pending;

                                                      do {
                                                        if (n.pending === n.pending_buf_size && (n.gzhead.hcrc && n.pending > i && (e.adler = p(e.adler, n.pending_buf, n.pending - i, i)), E(e), i = n.pending, n.pending === n.pending_buf_size)) {
                                                          s = 1;
                                                          break;
                                                        }

                                                        s = n.gzindex < n.gzhead.name.length ? 255 & n.gzhead.name.charCodeAt(n.gzindex++) : 0, I(n, s);
                                                      } while (0 !== s);

                                                      n.gzhead.hcrc && n.pending > i && (e.adler = p(e.adler, n.pending_buf, n.pending - i, i)), 0 === s && (n.gzindex = 0, n.status = 91);
                                                    } else n.status = 91;
                                                    if (91 === n.status) if (n.gzhead.comment) {
                                                      i = n.pending;

                                                      do {
                                                        if (n.pending === n.pending_buf_size && (n.gzhead.hcrc && n.pending > i && (e.adler = p(e.adler, n.pending_buf, n.pending - i, i)), E(e), i = n.pending, n.pending === n.pending_buf_size)) {
                                                          s = 1;
                                                          break;
                                                        }

                                                        s = n.gzindex < n.gzhead.comment.length ? 255 & n.gzhead.comment.charCodeAt(n.gzindex++) : 0, I(n, s);
                                                      } while (0 !== s);

                                                      n.gzhead.hcrc && n.pending > i && (e.adler = p(e.adler, n.pending_buf, n.pending - i, i)), 0 === s && (n.status = 103);
                                                    } else n.status = 103;

                                                    if (103 === n.status && (n.gzhead.hcrc ? (n.pending + 2 > n.pending_buf_size && E(e), n.pending + 2 <= n.pending_buf_size && (I(n, 255 & e.adler), I(n, e.adler >> 8 & 255), e.adler = 0, n.status = x)) : n.status = x), 0 !== n.pending) {
                                                      if (E(e), 0 === e.avail_out) return n.last_flush = -1, l;
                                                    } else if (0 === e.avail_in && z(t) <= z(r) && 4 !== t) return S(e, -5);

                                                    if (666 === n.status && 0 !== e.avail_in) return S(e, -5);

                                                    if (0 !== e.avail_in || 0 !== n.lookahead || t !== f && 666 !== n.status) {
                                                      var o = 2 === n.strategy ? function (e, t) {
                                                        for (var r;;) {
                                                          if (0 === e.lookahead && (R(e), 0 === e.lookahead)) {
                                                            if (t === f) return 1;
                                                            break;
                                                          }

                                                          if (e.match_length = 0, r = h._tr_tally(e, 0, e.window[e.strstart]), e.lookahead--, e.strstart++, r && (A(e, !1), 0 === e.strm.avail_out)) return 1;
                                                        }

                                                        return e.insert = 0, 4 === t ? (A(e, !0), 0 === e.strm.avail_out ? 3 : 4) : e.last_lit && (A(e, !1), 0 === e.strm.avail_out) ? 1 : 2;
                                                      }(n, t) : 3 === n.strategy ? function (e, t) {
                                                        for (var r, n, i, s, a = e.window;;) {
                                                          if (e.lookahead <= w) {
                                                            if (R(e), e.lookahead <= w && t === f) return 1;
                                                            if (0 === e.lookahead) break;
                                                          }

                                                          if (e.match_length = 0, e.lookahead >= b && 0 < e.strstart && (n = a[i = e.strstart - 1]) === a[++i] && n === a[++i] && n === a[++i]) {
                                                            s = e.strstart + w;

                                                            do {} while (n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && n === a[++i] && i < s);

                                                            e.match_length = w - (s - i), e.match_length > e.lookahead && (e.match_length = e.lookahead);
                                                          }

                                                          if (e.match_length >= b ? (r = h._tr_tally(e, 1, e.match_length - b), e.lookahead -= e.match_length, e.strstart += e.match_length, e.match_length = 0) : (r = h._tr_tally(e, 0, e.window[e.strstart]), e.lookahead--, e.strstart++), r && (A(e, !1), 0 === e.strm.avail_out)) return 1;
                                                        }

                                                        return e.insert = 0, 4 === t ? (A(e, !0), 0 === e.strm.avail_out ? 3 : 4) : e.last_lit && (A(e, !1), 0 === e.strm.avail_out) ? 1 : 2;
                                                      }(n, t) : u[n.level].func(n, t);
                                                      if (3 !== o && 4 !== o || (n.status = 666), 1 === o || 3 === o) return 0 === e.avail_out && (n.last_flush = -1), l;
                                                      if (2 === o && (1 === t ? h._tr_align(n) : 5 !== t && (h._tr_stored_block(n, 0, 0, !1), 3 === t && (C(n.head), 0 === n.lookahead && (n.strstart = 0, n.block_start = 0, n.insert = 0))), E(e), 0 === e.avail_out)) return n.last_flush = -1, l;
                                                    }

                                                    return 4 !== t ? l : n.wrap <= 0 ? 1 : (2 === n.wrap ? (I(n, 255 & e.adler), I(n, e.adler >> 8 & 255), I(n, e.adler >> 16 & 255), I(n, e.adler >> 24 & 255), I(n, 255 & e.total_in), I(n, e.total_in >> 8 & 255), I(n, e.total_in >> 16 & 255), I(n, e.total_in >> 24 & 255)) : (O(n, e.adler >>> 16), O(n, 65535 & e.adler)), E(e), 0 < n.wrap && (n.wrap = -n.wrap), 0 !== n.pending ? l : 1);
                                                  }, r.deflateEnd = function (e) {
                                                    var t;
                                                    return e && e.state ? (t = e.state.status) !== k && 69 !== t && 73 !== t && 91 !== t && 103 !== t && t !== x && 666 !== t ? S(e, m) : (e.state = null, t === x ? S(e, -3) : l) : m;
                                                  }, r.deflateSetDictionary = function (e, t) {
                                                    var r,
                                                        n,
                                                        i,
                                                        s,
                                                        a,
                                                        o,
                                                        u,
                                                        h,
                                                        f = t.length;
                                                    if (!e || !e.state) return m;
                                                    if (2 === (s = (r = e.state).wrap) || 1 === s && r.status !== k || r.lookahead) return m;

                                                    for (1 === s && (e.adler = c(e.adler, t, f, 0)), r.wrap = 0, f >= r.w_size && (0 === s && (C(r.head), r.strstart = 0, r.block_start = 0, r.insert = 0), h = new d.Buf8(r.w_size), d.arraySet(h, t, f - r.w_size, r.w_size, 0), t = h, f = r.w_size), a = e.avail_in, o = e.next_in, u = e.input, e.avail_in = f, e.next_in = 0, e.input = t, R(r); r.lookahead >= b;) {
                                                      for (n = r.strstart, i = r.lookahead - (b - 1); r.ins_h = (r.ins_h << r.hash_shift ^ r.window[n + b - 1]) & r.hash_mask, r.prev[n & r.w_mask] = r.head[r.ins_h], r.head[r.ins_h] = n, n++, --i;);

                                                      r.strstart = n, r.lookahead = b - 1, R(r);
                                                    }

                                                    return r.strstart += r.lookahead, r.block_start = r.strstart, r.insert = r.lookahead, r.lookahead = 0, r.match_length = r.prev_length = b - 1, r.match_available = 0, e.next_in = o, e.input = u, e.avail_in = a, r.wrap = s, l;
                                                  }, r.deflateInfo = "pako deflate (from Nodeca project)";
                                                }, {
                                                  "../utils/common": 41,
                                                  "./adler32": 43,
                                                  "./crc32": 45,
                                                  "./messages": 51,
                                                  "./trees": 52
                                                }],
                                                47: [function (e, t, r) {

                                                  t.exports = function () {
                                                    this.text = 0, this.time = 0, this.xflags = 0, this.os = 0, this.extra = null, this.extra_len = 0, this.name = "", this.comment = "", this.hcrc = 0, this.done = !1;
                                                  };
                                                }, {}],
                                                48: [function (e, t, r) {

                                                  t.exports = function (e, t) {
                                                    var r, n, i, s, a, o, u, h, f, l, d, c, p, m, _, g, v, b, w, y, k, x, S, z, C;

                                                    r = e.state, n = e.next_in, z = e.input, i = n + (e.avail_in - 5), s = e.next_out, C = e.output, a = s - (t - e.avail_out), o = s + (e.avail_out - 257), u = r.dmax, h = r.wsize, f = r.whave, l = r.wnext, d = r.window, c = r.hold, p = r.bits, m = r.lencode, _ = r.distcode, g = (1 << r.lenbits) - 1, v = (1 << r.distbits) - 1;

                                                    e: do {
                                                      p < 15 && (c += z[n++] << p, p += 8, c += z[n++] << p, p += 8), b = m[c & g];

                                                      t: for (;;) {
                                                        if (c >>>= w = b >>> 24, p -= w, 0 == (w = b >>> 16 & 255)) C[s++] = 65535 & b;else {
                                                          if (!(16 & w)) {
                                                            if (0 == (64 & w)) {
                                                              b = m[(65535 & b) + (c & (1 << w) - 1)];
                                                              continue t;
                                                            }

                                                            if (32 & w) {
                                                              r.mode = 12;
                                                              break e;
                                                            }

                                                            e.msg = "invalid literal/length code", r.mode = 30;
                                                            break e;
                                                          }

                                                          y = 65535 & b, (w &= 15) && (p < w && (c += z[n++] << p, p += 8), y += c & (1 << w) - 1, c >>>= w, p -= w), p < 15 && (c += z[n++] << p, p += 8, c += z[n++] << p, p += 8), b = _[c & v];

                                                          r: for (;;) {
                                                            if (c >>>= w = b >>> 24, p -= w, !(16 & (w = b >>> 16 & 255))) {
                                                              if (0 == (64 & w)) {
                                                                b = _[(65535 & b) + (c & (1 << w) - 1)];
                                                                continue r;
                                                              }

                                                              e.msg = "invalid distance code", r.mode = 30;
                                                              break e;
                                                            }

                                                            if (k = 65535 & b, p < (w &= 15) && (c += z[n++] << p, (p += 8) < w && (c += z[n++] << p, p += 8)), u < (k += c & (1 << w) - 1)) {
                                                              e.msg = "invalid distance too far back", r.mode = 30;
                                                              break e;
                                                            }

                                                            if (c >>>= w, p -= w, (w = s - a) < k) {
                                                              if (f < (w = k - w) && r.sane) {
                                                                e.msg = "invalid distance too far back", r.mode = 30;
                                                                break e;
                                                              }

                                                              if (S = d, (x = 0) === l) {
                                                                if (x += h - w, w < y) {
                                                                  for (y -= w; C[s++] = d[x++], --w;);

                                                                  x = s - k, S = C;
                                                                }
                                                              } else if (l < w) {
                                                                if (x += h + l - w, (w -= l) < y) {
                                                                  for (y -= w; C[s++] = d[x++], --w;);

                                                                  if (x = 0, l < y) {
                                                                    for (y -= w = l; C[s++] = d[x++], --w;);

                                                                    x = s - k, S = C;
                                                                  }
                                                                }
                                                              } else if (x += l - w, w < y) {
                                                                for (y -= w; C[s++] = d[x++], --w;);

                                                                x = s - k, S = C;
                                                              }

                                                              for (; 2 < y;) C[s++] = S[x++], C[s++] = S[x++], C[s++] = S[x++], y -= 3;

                                                              y && (C[s++] = S[x++], 1 < y && (C[s++] = S[x++]));
                                                            } else {
                                                              for (x = s - k; C[s++] = C[x++], C[s++] = C[x++], C[s++] = C[x++], 2 < (y -= 3););

                                                              y && (C[s++] = C[x++], 1 < y && (C[s++] = C[x++]));
                                                            }

                                                            break;
                                                          }
                                                        }
                                                        break;
                                                      }
                                                    } while (n < i && s < o);

                                                    n -= y = p >> 3, c &= (1 << (p -= y << 3)) - 1, e.next_in = n, e.next_out = s, e.avail_in = n < i ? i - n + 5 : 5 - (n - i), e.avail_out = s < o ? o - s + 257 : 257 - (s - o), r.hold = c, r.bits = p;
                                                  };
                                                }, {}],
                                                49: [function (e, t, r) {

                                                  var I = e("../utils/common"),
                                                      O = e("./adler32"),
                                                      B = e("./crc32"),
                                                      R = e("./inffast"),
                                                      T = e("./inftrees"),
                                                      D = 1,
                                                      F = 2,
                                                      N = 0,
                                                      U = -2,
                                                      P = 1,
                                                      n = 852,
                                                      i = 592;

                                                  function L(e) {
                                                    return (e >>> 24 & 255) + (e >>> 8 & 65280) + ((65280 & e) << 8) + ((255 & e) << 24);
                                                  }

                                                  function s() {
                                                    this.mode = 0, this.last = !1, this.wrap = 0, this.havedict = !1, this.flags = 0, this.dmax = 0, this.check = 0, this.total = 0, this.head = null, this.wbits = 0, this.wsize = 0, this.whave = 0, this.wnext = 0, this.window = null, this.hold = 0, this.bits = 0, this.length = 0, this.offset = 0, this.extra = 0, this.lencode = null, this.distcode = null, this.lenbits = 0, this.distbits = 0, this.ncode = 0, this.nlen = 0, this.ndist = 0, this.have = 0, this.next = null, this.lens = new I.Buf16(320), this.work = new I.Buf16(288), this.lendyn = null, this.distdyn = null, this.sane = 0, this.back = 0, this.was = 0;
                                                  }

                                                  function a(e) {
                                                    var t;
                                                    return e && e.state ? (t = e.state, e.total_in = e.total_out = t.total = 0, e.msg = "", t.wrap && (e.adler = 1 & t.wrap), t.mode = P, t.last = 0, t.havedict = 0, t.dmax = 32768, t.head = null, t.hold = 0, t.bits = 0, t.lencode = t.lendyn = new I.Buf32(n), t.distcode = t.distdyn = new I.Buf32(i), t.sane = 1, t.back = -1, N) : U;
                                                  }

                                                  function o(e) {
                                                    var t;
                                                    return e && e.state ? ((t = e.state).wsize = 0, t.whave = 0, t.wnext = 0, a(e)) : U;
                                                  }

                                                  function u(e, t) {
                                                    var r, n;
                                                    return e && e.state ? (n = e.state, t < 0 ? (r = 0, t = -t) : (r = 1 + (t >> 4), t < 48 && (t &= 15)), t && (t < 8 || 15 < t) ? U : (null !== n.window && n.wbits !== t && (n.window = null), n.wrap = r, n.wbits = t, o(e))) : U;
                                                  }

                                                  function h(e, t) {
                                                    var r, n;
                                                    return e ? (n = new s(), (e.state = n).window = null, (r = u(e, t)) !== N && (e.state = null), r) : U;
                                                  }

                                                  var f,
                                                      l,
                                                      d = !0;

                                                  function j(e) {
                                                    if (d) {
                                                      var t;

                                                      for (f = new I.Buf32(512), l = new I.Buf32(32), t = 0; t < 144;) e.lens[t++] = 8;

                                                      for (; t < 256;) e.lens[t++] = 9;

                                                      for (; t < 280;) e.lens[t++] = 7;

                                                      for (; t < 288;) e.lens[t++] = 8;

                                                      for (T(D, e.lens, 0, 288, f, 0, e.work, {
                                                        bits: 9
                                                      }), t = 0; t < 32;) e.lens[t++] = 5;

                                                      T(F, e.lens, 0, 32, l, 0, e.work, {
                                                        bits: 5
                                                      }), d = !1;
                                                    }

                                                    e.lencode = f, e.lenbits = 9, e.distcode = l, e.distbits = 5;
                                                  }

                                                  function Z(e, t, r, n) {
                                                    var i,
                                                        s = e.state;
                                                    return null === s.window && (s.wsize = 1 << s.wbits, s.wnext = 0, s.whave = 0, s.window = new I.Buf8(s.wsize)), n >= s.wsize ? (I.arraySet(s.window, t, r - s.wsize, s.wsize, 0), s.wnext = 0, s.whave = s.wsize) : (n < (i = s.wsize - s.wnext) && (i = n), I.arraySet(s.window, t, r - n, i, s.wnext), (n -= i) ? (I.arraySet(s.window, t, r - n, n, 0), s.wnext = n, s.whave = s.wsize) : (s.wnext += i, s.wnext === s.wsize && (s.wnext = 0), s.whave < s.wsize && (s.whave += i))), 0;
                                                  }

                                                  r.inflateReset = o, r.inflateReset2 = u, r.inflateResetKeep = a, r.inflateInit = function (e) {
                                                    return h(e, 15);
                                                  }, r.inflateInit2 = h, r.inflate = function (e, t) {
                                                    var r,
                                                        n,
                                                        i,
                                                        s,
                                                        a,
                                                        o,
                                                        u,
                                                        h,
                                                        f,
                                                        l,
                                                        d,
                                                        c,
                                                        p,
                                                        m,
                                                        _,
                                                        g,
                                                        v,
                                                        b,
                                                        w,
                                                        y,
                                                        k,
                                                        x,
                                                        S,
                                                        z,
                                                        C = 0,
                                                        E = new I.Buf8(4),
                                                        A = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];

                                                    if (!e || !e.state || !e.output || !e.input && 0 !== e.avail_in) return U;
                                                    12 === (r = e.state).mode && (r.mode = 13), a = e.next_out, i = e.output, u = e.avail_out, s = e.next_in, n = e.input, o = e.avail_in, h = r.hold, f = r.bits, l = o, d = u, x = N;

                                                    e: for (;;) switch (r.mode) {
                                                      case P:
                                                        if (0 === r.wrap) {
                                                          r.mode = 13;
                                                          break;
                                                        }

                                                        for (; f < 16;) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        if (2 & r.wrap && 35615 === h) {
                                                          E[r.check = 0] = 255 & h, E[1] = h >>> 8 & 255, r.check = B(r.check, E, 2, 0), f = h = 0, r.mode = 2;
                                                          break;
                                                        }

                                                        if (r.flags = 0, r.head && (r.head.done = !1), !(1 & r.wrap) || (((255 & h) << 8) + (h >> 8)) % 31) {
                                                          e.msg = "incorrect header check", r.mode = 30;
                                                          break;
                                                        }

                                                        if (8 != (15 & h)) {
                                                          e.msg = "unknown compression method", r.mode = 30;
                                                          break;
                                                        }

                                                        if (f -= 4, k = 8 + (15 & (h >>>= 4)), 0 === r.wbits) r.wbits = k;else if (k > r.wbits) {
                                                          e.msg = "invalid window size", r.mode = 30;
                                                          break;
                                                        }
                                                        r.dmax = 1 << k, e.adler = r.check = 1, r.mode = 512 & h ? 10 : 12, f = h = 0;
                                                        break;

                                                      case 2:
                                                        for (; f < 16;) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        if (r.flags = h, 8 != (255 & r.flags)) {
                                                          e.msg = "unknown compression method", r.mode = 30;
                                                          break;
                                                        }

                                                        if (57344 & r.flags) {
                                                          e.msg = "unknown header flags set", r.mode = 30;
                                                          break;
                                                        }

                                                        r.head && (r.head.text = h >> 8 & 1), 512 & r.flags && (E[0] = 255 & h, E[1] = h >>> 8 & 255, r.check = B(r.check, E, 2, 0)), f = h = 0, r.mode = 3;

                                                      case 3:
                                                        for (; f < 32;) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        r.head && (r.head.time = h), 512 & r.flags && (E[0] = 255 & h, E[1] = h >>> 8 & 255, E[2] = h >>> 16 & 255, E[3] = h >>> 24 & 255, r.check = B(r.check, E, 4, 0)), f = h = 0, r.mode = 4;

                                                      case 4:
                                                        for (; f < 16;) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        r.head && (r.head.xflags = 255 & h, r.head.os = h >> 8), 512 & r.flags && (E[0] = 255 & h, E[1] = h >>> 8 & 255, r.check = B(r.check, E, 2, 0)), f = h = 0, r.mode = 5;

                                                      case 5:
                                                        if (1024 & r.flags) {
                                                          for (; f < 16;) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          r.length = h, r.head && (r.head.extra_len = h), 512 & r.flags && (E[0] = 255 & h, E[1] = h >>> 8 & 255, r.check = B(r.check, E, 2, 0)), f = h = 0;
                                                        } else r.head && (r.head.extra = null);

                                                        r.mode = 6;

                                                      case 6:
                                                        if (1024 & r.flags && (o < (c = r.length) && (c = o), c && (r.head && (k = r.head.extra_len - r.length, r.head.extra || (r.head.extra = new Array(r.head.extra_len)), I.arraySet(r.head.extra, n, s, c, k)), 512 & r.flags && (r.check = B(r.check, n, c, s)), o -= c, s += c, r.length -= c), r.length)) break e;
                                                        r.length = 0, r.mode = 7;

                                                      case 7:
                                                        if (2048 & r.flags) {
                                                          if (0 === o) break e;

                                                          for (c = 0; k = n[s + c++], r.head && k && r.length < 65536 && (r.head.name += String.fromCharCode(k)), k && c < o;);

                                                          if (512 & r.flags && (r.check = B(r.check, n, c, s)), o -= c, s += c, k) break e;
                                                        } else r.head && (r.head.name = null);

                                                        r.length = 0, r.mode = 8;

                                                      case 8:
                                                        if (4096 & r.flags) {
                                                          if (0 === o) break e;

                                                          for (c = 0; k = n[s + c++], r.head && k && r.length < 65536 && (r.head.comment += String.fromCharCode(k)), k && c < o;);

                                                          if (512 & r.flags && (r.check = B(r.check, n, c, s)), o -= c, s += c, k) break e;
                                                        } else r.head && (r.head.comment = null);

                                                        r.mode = 9;

                                                      case 9:
                                                        if (512 & r.flags) {
                                                          for (; f < 16;) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          if (h !== (65535 & r.check)) {
                                                            e.msg = "header crc mismatch", r.mode = 30;
                                                            break;
                                                          }

                                                          f = h = 0;
                                                        }

                                                        r.head && (r.head.hcrc = r.flags >> 9 & 1, r.head.done = !0), e.adler = r.check = 0, r.mode = 12;
                                                        break;

                                                      case 10:
                                                        for (; f < 32;) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        e.adler = r.check = L(h), f = h = 0, r.mode = 11;

                                                      case 11:
                                                        if (0 === r.havedict) return e.next_out = a, e.avail_out = u, e.next_in = s, e.avail_in = o, r.hold = h, r.bits = f, 2;
                                                        e.adler = r.check = 1, r.mode = 12;

                                                      case 12:
                                                        if (5 === t || 6 === t) break e;

                                                      case 13:
                                                        if (r.last) {
                                                          h >>>= 7 & f, f -= 7 & f, r.mode = 27;
                                                          break;
                                                        }

                                                        for (; f < 3;) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        switch (r.last = 1 & h, f -= 1, 3 & (h >>>= 1)) {
                                                          case 0:
                                                            r.mode = 14;
                                                            break;

                                                          case 1:
                                                            if (j(r), r.mode = 20, 6 !== t) break;
                                                            h >>>= 2, f -= 2;
                                                            break e;

                                                          case 2:
                                                            r.mode = 17;
                                                            break;

                                                          case 3:
                                                            e.msg = "invalid block type", r.mode = 30;
                                                        }

                                                        h >>>= 2, f -= 2;
                                                        break;

                                                      case 14:
                                                        for (h >>>= 7 & f, f -= 7 & f; f < 32;) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        if ((65535 & h) != (h >>> 16 ^ 65535)) {
                                                          e.msg = "invalid stored block lengths", r.mode = 30;
                                                          break;
                                                        }

                                                        if (r.length = 65535 & h, f = h = 0, r.mode = 15, 6 === t) break e;

                                                      case 15:
                                                        r.mode = 16;

                                                      case 16:
                                                        if (c = r.length) {
                                                          if (o < c && (c = o), u < c && (c = u), 0 === c) break e;
                                                          I.arraySet(i, n, s, c, a), o -= c, s += c, u -= c, a += c, r.length -= c;
                                                          break;
                                                        }

                                                        r.mode = 12;
                                                        break;

                                                      case 17:
                                                        for (; f < 14;) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        if (r.nlen = 257 + (31 & h), h >>>= 5, f -= 5, r.ndist = 1 + (31 & h), h >>>= 5, f -= 5, r.ncode = 4 + (15 & h), h >>>= 4, f -= 4, 286 < r.nlen || 30 < r.ndist) {
                                                          e.msg = "too many length or distance symbols", r.mode = 30;
                                                          break;
                                                        }

                                                        r.have = 0, r.mode = 18;

                                                      case 18:
                                                        for (; r.have < r.ncode;) {
                                                          for (; f < 3;) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          r.lens[A[r.have++]] = 7 & h, h >>>= 3, f -= 3;
                                                        }

                                                        for (; r.have < 19;) r.lens[A[r.have++]] = 0;

                                                        if (r.lencode = r.lendyn, r.lenbits = 7, S = {
                                                          bits: r.lenbits
                                                        }, x = T(0, r.lens, 0, 19, r.lencode, 0, r.work, S), r.lenbits = S.bits, x) {
                                                          e.msg = "invalid code lengths set", r.mode = 30;
                                                          break;
                                                        }

                                                        r.have = 0, r.mode = 19;

                                                      case 19:
                                                        for (; r.have < r.nlen + r.ndist;) {
                                                          for (; g = (C = r.lencode[h & (1 << r.lenbits) - 1]) >>> 16 & 255, v = 65535 & C, !((_ = C >>> 24) <= f);) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          if (v < 16) h >>>= _, f -= _, r.lens[r.have++] = v;else {
                                                            if (16 === v) {
                                                              for (z = _ + 2; f < z;) {
                                                                if (0 === o) break e;
                                                                o--, h += n[s++] << f, f += 8;
                                                              }

                                                              if (h >>>= _, f -= _, 0 === r.have) {
                                                                e.msg = "invalid bit length repeat", r.mode = 30;
                                                                break;
                                                              }

                                                              k = r.lens[r.have - 1], c = 3 + (3 & h), h >>>= 2, f -= 2;
                                                            } else if (17 === v) {
                                                              for (z = _ + 3; f < z;) {
                                                                if (0 === o) break e;
                                                                o--, h += n[s++] << f, f += 8;
                                                              }

                                                              f -= _, k = 0, c = 3 + (7 & (h >>>= _)), h >>>= 3, f -= 3;
                                                            } else {
                                                              for (z = _ + 7; f < z;) {
                                                                if (0 === o) break e;
                                                                o--, h += n[s++] << f, f += 8;
                                                              }

                                                              f -= _, k = 0, c = 11 + (127 & (h >>>= _)), h >>>= 7, f -= 7;
                                                            }

                                                            if (r.have + c > r.nlen + r.ndist) {
                                                              e.msg = "invalid bit length repeat", r.mode = 30;
                                                              break;
                                                            }

                                                            for (; c--;) r.lens[r.have++] = k;
                                                          }
                                                        }

                                                        if (30 === r.mode) break;

                                                        if (0 === r.lens[256]) {
                                                          e.msg = "invalid code -- missing end-of-block", r.mode = 30;
                                                          break;
                                                        }

                                                        if (r.lenbits = 9, S = {
                                                          bits: r.lenbits
                                                        }, x = T(D, r.lens, 0, r.nlen, r.lencode, 0, r.work, S), r.lenbits = S.bits, x) {
                                                          e.msg = "invalid literal/lengths set", r.mode = 30;
                                                          break;
                                                        }

                                                        if (r.distbits = 6, r.distcode = r.distdyn, S = {
                                                          bits: r.distbits
                                                        }, x = T(F, r.lens, r.nlen, r.ndist, r.distcode, 0, r.work, S), r.distbits = S.bits, x) {
                                                          e.msg = "invalid distances set", r.mode = 30;
                                                          break;
                                                        }

                                                        if (r.mode = 20, 6 === t) break e;

                                                      case 20:
                                                        r.mode = 21;

                                                      case 21:
                                                        if (6 <= o && 258 <= u) {
                                                          e.next_out = a, e.avail_out = u, e.next_in = s, e.avail_in = o, r.hold = h, r.bits = f, R(e, d), a = e.next_out, i = e.output, u = e.avail_out, s = e.next_in, n = e.input, o = e.avail_in, h = r.hold, f = r.bits, 12 === r.mode && (r.back = -1);
                                                          break;
                                                        }

                                                        for (r.back = 0; g = (C = r.lencode[h & (1 << r.lenbits) - 1]) >>> 16 & 255, v = 65535 & C, !((_ = C >>> 24) <= f);) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        if (g && 0 == (240 & g)) {
                                                          for (b = _, w = g, y = v; g = (C = r.lencode[y + ((h & (1 << b + w) - 1) >> b)]) >>> 16 & 255, v = 65535 & C, !(b + (_ = C >>> 24) <= f);) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          h >>>= b, f -= b, r.back += b;
                                                        }

                                                        if (h >>>= _, f -= _, r.back += _, r.length = v, 0 === g) {
                                                          r.mode = 26;
                                                          break;
                                                        }

                                                        if (32 & g) {
                                                          r.back = -1, r.mode = 12;
                                                          break;
                                                        }

                                                        if (64 & g) {
                                                          e.msg = "invalid literal/length code", r.mode = 30;
                                                          break;
                                                        }

                                                        r.extra = 15 & g, r.mode = 22;

                                                      case 22:
                                                        if (r.extra) {
                                                          for (z = r.extra; f < z;) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          r.length += h & (1 << r.extra) - 1, h >>>= r.extra, f -= r.extra, r.back += r.extra;
                                                        }

                                                        r.was = r.length, r.mode = 23;

                                                      case 23:
                                                        for (; g = (C = r.distcode[h & (1 << r.distbits) - 1]) >>> 16 & 255, v = 65535 & C, !((_ = C >>> 24) <= f);) {
                                                          if (0 === o) break e;
                                                          o--, h += n[s++] << f, f += 8;
                                                        }

                                                        if (0 == (240 & g)) {
                                                          for (b = _, w = g, y = v; g = (C = r.distcode[y + ((h & (1 << b + w) - 1) >> b)]) >>> 16 & 255, v = 65535 & C, !(b + (_ = C >>> 24) <= f);) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          h >>>= b, f -= b, r.back += b;
                                                        }

                                                        if (h >>>= _, f -= _, r.back += _, 64 & g) {
                                                          e.msg = "invalid distance code", r.mode = 30;
                                                          break;
                                                        }

                                                        r.offset = v, r.extra = 15 & g, r.mode = 24;

                                                      case 24:
                                                        if (r.extra) {
                                                          for (z = r.extra; f < z;) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          r.offset += h & (1 << r.extra) - 1, h >>>= r.extra, f -= r.extra, r.back += r.extra;
                                                        }

                                                        if (r.offset > r.dmax) {
                                                          e.msg = "invalid distance too far back", r.mode = 30;
                                                          break;
                                                        }

                                                        r.mode = 25;

                                                      case 25:
                                                        if (0 === u) break e;

                                                        if (c = d - u, r.offset > c) {
                                                          if ((c = r.offset - c) > r.whave && r.sane) {
                                                            e.msg = "invalid distance too far back", r.mode = 30;
                                                            break;
                                                          }

                                                          p = c > r.wnext ? (c -= r.wnext, r.wsize - c) : r.wnext - c, c > r.length && (c = r.length), m = r.window;
                                                        } else m = i, p = a - r.offset, c = r.length;

                                                        for (u < c && (c = u), u -= c, r.length -= c; i[a++] = m[p++], --c;);

                                                        0 === r.length && (r.mode = 21);
                                                        break;

                                                      case 26:
                                                        if (0 === u) break e;
                                                        i[a++] = r.length, u--, r.mode = 21;
                                                        break;

                                                      case 27:
                                                        if (r.wrap) {
                                                          for (; f < 32;) {
                                                            if (0 === o) break e;
                                                            o--, h |= n[s++] << f, f += 8;
                                                          }

                                                          if (d -= u, e.total_out += d, r.total += d, d && (e.adler = r.check = r.flags ? B(r.check, i, d, a - d) : O(r.check, i, d, a - d)), d = u, (r.flags ? h : L(h)) !== r.check) {
                                                            e.msg = "incorrect data check", r.mode = 30;
                                                            break;
                                                          }

                                                          f = h = 0;
                                                        }

                                                        r.mode = 28;

                                                      case 28:
                                                        if (r.wrap && r.flags) {
                                                          for (; f < 32;) {
                                                            if (0 === o) break e;
                                                            o--, h += n[s++] << f, f += 8;
                                                          }

                                                          if (h !== (4294967295 & r.total)) {
                                                            e.msg = "incorrect length check", r.mode = 30;
                                                            break;
                                                          }

                                                          f = h = 0;
                                                        }

                                                        r.mode = 29;

                                                      case 29:
                                                        x = 1;
                                                        break e;

                                                      case 30:
                                                        x = -3;
                                                        break e;

                                                      case 31:
                                                        return -4;

                                                      case 32:
                                                      default:
                                                        return U;
                                                    }

                                                    return e.next_out = a, e.avail_out = u, e.next_in = s, e.avail_in = o, r.hold = h, r.bits = f, (r.wsize || d !== e.avail_out && r.mode < 30 && (r.mode < 27 || 4 !== t)) && Z(e, e.output, e.next_out, d - e.avail_out) ? (r.mode = 31, -4) : (l -= e.avail_in, d -= e.avail_out, e.total_in += l, e.total_out += d, r.total += d, r.wrap && d && (e.adler = r.check = r.flags ? B(r.check, i, d, e.next_out - d) : O(r.check, i, d, e.next_out - d)), e.data_type = r.bits + (r.last ? 64 : 0) + (12 === r.mode ? 128 : 0) + (20 === r.mode || 15 === r.mode ? 256 : 0), (0 == l && 0 === d || 4 === t) && x === N && (x = -5), x);
                                                  }, r.inflateEnd = function (e) {
                                                    if (!e || !e.state) return U;
                                                    var t = e.state;
                                                    return t.window && (t.window = null), e.state = null, N;
                                                  }, r.inflateGetHeader = function (e, t) {
                                                    var r;
                                                    return e && e.state ? 0 == (2 & (r = e.state).wrap) ? U : ((r.head = t).done = !1, N) : U;
                                                  }, r.inflateSetDictionary = function (e, t) {
                                                    var r,
                                                        n = t.length;
                                                    return e && e.state ? 0 !== (r = e.state).wrap && 11 !== r.mode ? U : 11 === r.mode && O(1, t, n, 0) !== r.check ? -3 : Z(e, t, n, n) ? (r.mode = 31, -4) : (r.havedict = 1, N) : U;
                                                  }, r.inflateInfo = "pako inflate (from Nodeca project)";
                                                }, {
                                                  "../utils/common": 41,
                                                  "./adler32": 43,
                                                  "./crc32": 45,
                                                  "./inffast": 48,
                                                  "./inftrees": 50
                                                }],
                                                50: [function (e, t, r) {

                                                  var D = e("../utils/common"),
                                                      F = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0],
                                                      N = [16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78],
                                                      U = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0],
                                                      P = [16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64];

                                                  t.exports = function (e, t, r, n, i, s, a, o) {
                                                    var u,
                                                        h,
                                                        f,
                                                        l,
                                                        d,
                                                        c,
                                                        p,
                                                        m,
                                                        _,
                                                        g = o.bits,
                                                        v = 0,
                                                        b = 0,
                                                        w = 0,
                                                        y = 0,
                                                        k = 0,
                                                        x = 0,
                                                        S = 0,
                                                        z = 0,
                                                        C = 0,
                                                        E = 0,
                                                        A = null,
                                                        I = 0,
                                                        O = new D.Buf16(16),
                                                        B = new D.Buf16(16),
                                                        R = null,
                                                        T = 0;

                                                    for (v = 0; v <= 15; v++) O[v] = 0;

                                                    for (b = 0; b < n; b++) O[t[r + b]]++;

                                                    for (k = g, y = 15; 1 <= y && 0 === O[y]; y--);

                                                    if (y < k && (k = y), 0 === y) return i[s++] = 20971520, i[s++] = 20971520, o.bits = 1, 0;

                                                    for (w = 1; w < y && 0 === O[w]; w++);

                                                    for (k < w && (k = w), v = z = 1; v <= 15; v++) if (z <<= 1, (z -= O[v]) < 0) return -1;

                                                    if (0 < z && (0 === e || 1 !== y)) return -1;

                                                    for (B[1] = 0, v = 1; v < 15; v++) B[v + 1] = B[v] + O[v];

                                                    for (b = 0; b < n; b++) 0 !== t[r + b] && (a[B[t[r + b]]++] = b);

                                                    if (c = 0 === e ? (A = R = a, 19) : 1 === e ? (A = F, I -= 257, R = N, T -= 257, 256) : (A = U, R = P, -1), v = w, d = s, S = b = E = 0, f = -1, l = (C = 1 << (x = k)) - 1, 1 === e && 852 < C || 2 === e && 592 < C) return 1;

                                                    for (;;) {
                                                      for (p = v - S, _ = a[b] < c ? (m = 0, a[b]) : a[b] > c ? (m = R[T + a[b]], A[I + a[b]]) : (m = 96, 0), u = 1 << v - S, w = h = 1 << x; i[d + (E >> S) + (h -= u)] = p << 24 | m << 16 | _ | 0, 0 !== h;);

                                                      for (u = 1 << v - 1; E & u;) u >>= 1;

                                                      if (0 !== u ? (E &= u - 1, E += u) : E = 0, b++, 0 == --O[v]) {
                                                        if (v === y) break;
                                                        v = t[r + a[b]];
                                                      }

                                                      if (k < v && (E & l) !== f) {
                                                        for (0 === S && (S = k), d += w, z = 1 << (x = v - S); x + S < y && !((z -= O[x + S]) <= 0);) x++, z <<= 1;

                                                        if (C += 1 << x, 1 === e && 852 < C || 2 === e && 592 < C) return 1;
                                                        i[f = E & l] = k << 24 | x << 16 | d - s | 0;
                                                      }
                                                    }

                                                    return 0 !== E && (i[d + E] = v - S << 24 | 64 << 16 | 0), o.bits = k, 0;
                                                  };
                                                }, {
                                                  "../utils/common": 41
                                                }],
                                                51: [function (e, t, r) {

                                                  t.exports = {
                                                    2: "need dictionary",
                                                    1: "stream end",
                                                    0: "",
                                                    "-1": "file error",
                                                    "-2": "stream error",
                                                    "-3": "data error",
                                                    "-4": "insufficient memory",
                                                    "-5": "buffer error",
                                                    "-6": "incompatible version"
                                                  };
                                                }, {}],
                                                52: [function (e, t, r) {

                                                  var o = e("../utils/common");

                                                  function n(e) {
                                                    for (var t = e.length; 0 <= --t;) e[t] = 0;
                                                  }

                                                  var _ = 15,
                                                      i = 16,
                                                      u = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0],
                                                      h = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13],
                                                      a = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7],
                                                      f = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
                                                      l = new Array(576);
                                                  n(l);
                                                  var d = new Array(60);
                                                  n(d);
                                                  var c = new Array(512);
                                                  n(c);
                                                  var p = new Array(256);
                                                  n(p);
                                                  var m = new Array(29);
                                                  n(m);
                                                  var g,
                                                      v,
                                                      b,
                                                      w = new Array(30);

                                                  function y(e, t, r, n, i) {
                                                    this.static_tree = e, this.extra_bits = t, this.extra_base = r, this.elems = n, this.max_length = i, this.has_stree = e && e.length;
                                                  }

                                                  function s(e, t) {
                                                    this.dyn_tree = e, this.max_code = 0, this.stat_desc = t;
                                                  }

                                                  function k(e) {
                                                    return e < 256 ? c[e] : c[256 + (e >>> 7)];
                                                  }

                                                  function x(e, t) {
                                                    e.pending_buf[e.pending++] = 255 & t, e.pending_buf[e.pending++] = t >>> 8 & 255;
                                                  }

                                                  function S(e, t, r) {
                                                    e.bi_valid > i - r ? (e.bi_buf |= t << e.bi_valid & 65535, x(e, e.bi_buf), e.bi_buf = t >> i - e.bi_valid, e.bi_valid += r - i) : (e.bi_buf |= t << e.bi_valid & 65535, e.bi_valid += r);
                                                  }

                                                  function z(e, t, r) {
                                                    S(e, r[2 * t], r[2 * t + 1]);
                                                  }

                                                  function C(e, t) {
                                                    for (var r = 0; r |= 1 & e, e >>>= 1, r <<= 1, 0 < --t;);

                                                    return r >>> 1;
                                                  }

                                                  function E(e, t, r) {
                                                    var n,
                                                        i,
                                                        s = new Array(_ + 1),
                                                        a = 0;

                                                    for (n = 1; n <= _; n++) s[n] = a = a + r[n - 1] << 1;

                                                    for (i = 0; i <= t; i++) {
                                                      var o = e[2 * i + 1];
                                                      0 !== o && (e[2 * i] = C(s[o]++, o));
                                                    }
                                                  }

                                                  function A(e) {
                                                    var t;

                                                    for (t = 0; t < 286; t++) e.dyn_ltree[2 * t] = 0;

                                                    for (t = 0; t < 30; t++) e.dyn_dtree[2 * t] = 0;

                                                    for (t = 0; t < 19; t++) e.bl_tree[2 * t] = 0;

                                                    e.dyn_ltree[512] = 1, e.opt_len = e.static_len = 0, e.last_lit = e.matches = 0;
                                                  }

                                                  function I(e) {
                                                    8 < e.bi_valid ? x(e, e.bi_buf) : 0 < e.bi_valid && (e.pending_buf[e.pending++] = e.bi_buf), e.bi_buf = 0, e.bi_valid = 0;
                                                  }

                                                  function O(e, t, r, n) {
                                                    var i = 2 * t,
                                                        s = 2 * r;
                                                    return e[i] < e[s] || e[i] === e[s] && n[t] <= n[r];
                                                  }

                                                  function B(e, t, r) {
                                                    for (var n = e.heap[r], i = r << 1; i <= e.heap_len && (i < e.heap_len && O(t, e.heap[i + 1], e.heap[i], e.depth) && i++, !O(t, n, e.heap[i], e.depth));) e.heap[r] = e.heap[i], r = i, i <<= 1;

                                                    e.heap[r] = n;
                                                  }

                                                  function R(e, t, r) {
                                                    var n,
                                                        i,
                                                        s,
                                                        a,
                                                        o = 0;
                                                    if (0 !== e.last_lit) for (; n = e.pending_buf[e.d_buf + 2 * o] << 8 | e.pending_buf[e.d_buf + 2 * o + 1], i = e.pending_buf[e.l_buf + o], o++, 0 === n ? z(e, i, t) : (z(e, (s = p[i]) + 256 + 1, t), 0 !== (a = u[s]) && S(e, i -= m[s], a), z(e, s = k(--n), r), 0 !== (a = h[s]) && S(e, n -= w[s], a)), o < e.last_lit;);
                                                    z(e, 256, t);
                                                  }

                                                  function T(e, t) {
                                                    var r,
                                                        n,
                                                        i,
                                                        s = t.dyn_tree,
                                                        a = t.stat_desc.static_tree,
                                                        o = t.stat_desc.has_stree,
                                                        u = t.stat_desc.elems,
                                                        h = -1;

                                                    for (e.heap_len = 0, e.heap_max = 573, r = 0; r < u; r++) 0 !== s[2 * r] ? (e.heap[++e.heap_len] = h = r, e.depth[r] = 0) : s[2 * r + 1] = 0;

                                                    for (; e.heap_len < 2;) s[2 * (i = e.heap[++e.heap_len] = h < 2 ? ++h : 0)] = 1, e.depth[i] = 0, e.opt_len--, o && (e.static_len -= a[2 * i + 1]);

                                                    for (t.max_code = h, r = e.heap_len >> 1; 1 <= r; r--) B(e, s, r);

                                                    for (i = u; r = e.heap[1], e.heap[1] = e.heap[e.heap_len--], B(e, s, 1), n = e.heap[1], e.heap[--e.heap_max] = r, e.heap[--e.heap_max] = n, s[2 * i] = s[2 * r] + s[2 * n], e.depth[i] = (e.depth[r] >= e.depth[n] ? e.depth[r] : e.depth[n]) + 1, s[2 * r + 1] = s[2 * n + 1] = i, e.heap[1] = i++, B(e, s, 1), 2 <= e.heap_len;);

                                                    e.heap[--e.heap_max] = e.heap[1], function (e, t) {
                                                      var r,
                                                          n,
                                                          i,
                                                          s,
                                                          a,
                                                          o,
                                                          u = t.dyn_tree,
                                                          h = t.max_code,
                                                          f = t.stat_desc.static_tree,
                                                          l = t.stat_desc.has_stree,
                                                          d = t.stat_desc.extra_bits,
                                                          c = t.stat_desc.extra_base,
                                                          p = t.stat_desc.max_length,
                                                          m = 0;

                                                      for (s = 0; s <= _; s++) e.bl_count[s] = 0;

                                                      for (u[2 * e.heap[e.heap_max] + 1] = 0, r = e.heap_max + 1; r < 573; r++) p < (s = u[2 * u[2 * (n = e.heap[r]) + 1] + 1] + 1) && (s = p, m++), u[2 * n + 1] = s, h < n || (e.bl_count[s]++, a = 0, c <= n && (a = d[n - c]), o = u[2 * n], e.opt_len += o * (s + a), l && (e.static_len += o * (f[2 * n + 1] + a)));

                                                      if (0 !== m) {
                                                        do {
                                                          for (s = p - 1; 0 === e.bl_count[s];) s--;

                                                          e.bl_count[s]--, e.bl_count[s + 1] += 2, e.bl_count[p]--, m -= 2;
                                                        } while (0 < m);

                                                        for (s = p; 0 !== s; s--) for (n = e.bl_count[s]; 0 !== n;) h < (i = e.heap[--r]) || (u[2 * i + 1] !== s && (e.opt_len += (s - u[2 * i + 1]) * u[2 * i], u[2 * i + 1] = s), n--);
                                                      }
                                                    }(e, t), E(s, h, e.bl_count);
                                                  }

                                                  function D(e, t, r) {
                                                    var n,
                                                        i,
                                                        s = -1,
                                                        a = t[1],
                                                        o = 0,
                                                        u = 7,
                                                        h = 4;

                                                    for (0 === a && (u = 138, h = 3), t[2 * (r + 1) + 1] = 65535, n = 0; n <= r; n++) i = a, a = t[2 * (n + 1) + 1], ++o < u && i === a || (o < h ? e.bl_tree[2 * i] += o : 0 !== i ? (i !== s && e.bl_tree[2 * i]++, e.bl_tree[32]++) : o <= 10 ? e.bl_tree[34]++ : e.bl_tree[36]++, s = i, h = (o = 0) === a ? (u = 138, 3) : i === a ? (u = 6, 3) : (u = 7, 4));
                                                  }

                                                  function F(e, t, r) {
                                                    var n,
                                                        i,
                                                        s = -1,
                                                        a = t[1],
                                                        o = 0,
                                                        u = 7,
                                                        h = 4;

                                                    for (0 === a && (u = 138, h = 3), n = 0; n <= r; n++) if (i = a, a = t[2 * (n + 1) + 1], !(++o < u && i === a)) {
                                                      if (o < h) for (; z(e, i, e.bl_tree), 0 != --o;);else 0 !== i ? (i !== s && (z(e, i, e.bl_tree), o--), z(e, 16, e.bl_tree), S(e, o - 3, 2)) : o <= 10 ? (z(e, 17, e.bl_tree), S(e, o - 3, 3)) : (z(e, 18, e.bl_tree), S(e, o - 11, 7));
                                                      s = i, h = (o = 0) === a ? (u = 138, 3) : i === a ? (u = 6, 3) : (u = 7, 4);
                                                    }
                                                  }

                                                  n(w);
                                                  var N = !1;

                                                  function U(e, t, r, n) {
                                                    var i, s, a;
                                                    S(e, 0 + (n ? 1 : 0), 3), s = t, a = r, I(i = e), x(i, a), x(i, ~a), o.arraySet(i.pending_buf, i.window, s, a, i.pending), i.pending += a;
                                                  }

                                                  r._tr_init = function (e) {
                                                    N || (function () {
                                                      var e,
                                                          t,
                                                          r,
                                                          n,
                                                          i,
                                                          s = new Array(_ + 1);

                                                      for (n = r = 0; n < 28; n++) for (m[n] = r, e = 0; e < 1 << u[n]; e++) p[r++] = n;

                                                      for (p[r - 1] = n, n = i = 0; n < 16; n++) for (w[n] = i, e = 0; e < 1 << h[n]; e++) c[i++] = n;

                                                      for (i >>= 7; n < 30; n++) for (w[n] = i << 7, e = 0; e < 1 << h[n] - 7; e++) c[256 + i++] = n;

                                                      for (t = 0; t <= _; t++) s[t] = 0;

                                                      for (e = 0; e <= 143;) l[2 * e + 1] = 8, e++, s[8]++;

                                                      for (; e <= 255;) l[2 * e + 1] = 9, e++, s[9]++;

                                                      for (; e <= 279;) l[2 * e + 1] = 7, e++, s[7]++;

                                                      for (; e <= 287;) l[2 * e + 1] = 8, e++, s[8]++;

                                                      for (E(l, 287, s), e = 0; e < 30; e++) d[2 * e + 1] = 5, d[2 * e] = C(e, 5);

                                                      g = new y(l, u, 257, 286, _), v = new y(d, h, 0, 30, _), b = new y(new Array(0), a, 0, 19, 7);
                                                    }(), N = !0), e.l_desc = new s(e.dyn_ltree, g), e.d_desc = new s(e.dyn_dtree, v), e.bl_desc = new s(e.bl_tree, b), e.bi_buf = 0, e.bi_valid = 0, A(e);
                                                  }, r._tr_stored_block = U, r._tr_flush_block = function (e, t, r, n) {
                                                    var i,
                                                        s,
                                                        a = 0;
                                                    0 < e.level ? (2 === e.strm.data_type && (e.strm.data_type = function (e) {
                                                      var t,
                                                          r = 4093624447;

                                                      for (t = 0; t <= 31; t++, r >>>= 1) if (1 & r && 0 !== e.dyn_ltree[2 * t]) return 0;

                                                      if (0 !== e.dyn_ltree[18] || 0 !== e.dyn_ltree[20] || 0 !== e.dyn_ltree[26]) return 1;

                                                      for (t = 32; t < 256; t++) if (0 !== e.dyn_ltree[2 * t]) return 1;

                                                      return 0;
                                                    }(e)), T(e, e.l_desc), T(e, e.d_desc), a = function (e) {
                                                      var t;

                                                      for (D(e, e.dyn_ltree, e.l_desc.max_code), D(e, e.dyn_dtree, e.d_desc.max_code), T(e, e.bl_desc), t = 18; 3 <= t && 0 === e.bl_tree[2 * f[t] + 1]; t--);

                                                      return e.opt_len += 3 * (t + 1) + 5 + 5 + 4, t;
                                                    }(e), i = e.opt_len + 3 + 7 >>> 3, (s = e.static_len + 3 + 7 >>> 3) <= i && (i = s)) : i = s = r + 5, r + 4 <= i && -1 !== t ? U(e, t, r, n) : 4 === e.strategy || s === i ? (S(e, 2 + (n ? 1 : 0), 3), R(e, l, d)) : (S(e, 4 + (n ? 1 : 0), 3), function (e, t, r, n) {
                                                      var i;

                                                      for (S(e, t - 257, 5), S(e, r - 1, 5), S(e, n - 4, 4), i = 0; i < n; i++) S(e, e.bl_tree[2 * f[i] + 1], 3);

                                                      F(e, e.dyn_ltree, t - 1), F(e, e.dyn_dtree, r - 1);
                                                    }(e, e.l_desc.max_code + 1, e.d_desc.max_code + 1, a + 1), R(e, e.dyn_ltree, e.dyn_dtree)), A(e), n && I(e);
                                                  }, r._tr_tally = function (e, t, r) {
                                                    return e.pending_buf[e.d_buf + 2 * e.last_lit] = t >>> 8 & 255, e.pending_buf[e.d_buf + 2 * e.last_lit + 1] = 255 & t, e.pending_buf[e.l_buf + e.last_lit] = 255 & r, e.last_lit++, 0 === t ? e.dyn_ltree[2 * r]++ : (e.matches++, t--, e.dyn_ltree[2 * (p[r] + 256 + 1)]++, e.dyn_dtree[2 * k(t)]++), e.last_lit === e.lit_bufsize - 1;
                                                  }, r._tr_align = function (e) {
                                                    var t;
                                                    S(e, 2, 3), z(e, 256, l), 16 === (t = e).bi_valid ? (x(t, t.bi_buf), t.bi_buf = 0, t.bi_valid = 0) : 8 <= t.bi_valid && (t.pending_buf[t.pending++] = 255 & t.bi_buf, t.bi_buf >>= 8, t.bi_valid -= 8);
                                                  };
                                                }, {
                                                  "../utils/common": 41
                                                }],
                                                53: [function (e, t, r) {

                                                  t.exports = function () {
                                                    this.input = null, this.next_in = 0, this.avail_in = 0, this.total_in = 0, this.output = null, this.next_out = 0, this.avail_out = 0, this.total_out = 0, this.msg = "", this.state = null, this.data_type = 2, this.adler = 0;
                                                  };
                                                }, {}],
                                                54: [function (e, t, r) {

                                                  t.exports = "function" == typeof setImmediate ? setImmediate : function () {
                                                    var e = [].slice.apply(arguments);
                                                    e.splice(1, 0, 0), setTimeout.apply(null, e);
                                                  };
                                                }, {}]
                                              }, {}, [10])(10);
                                            });
                                          }).call(this, void 0 !== r ? r : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {});
                                        }, {}]
                                      }, {}, [1])(1);
                                    });
                                  }).call(this, void 0 !== r ? r : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {});
                                }, {}]
                              }, {}, [1])(1);
                            });
                          }).call(this, void 0 !== r ? r : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {});
                        }, {}]
                      }, {}, [1])(1);
                    });
                  }).call(this, "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {});
                }, {}]
              }, {}, [1])(1);
            });
          }).call(this, typeof commonjsGlobal$1 !== "undefined" ? commonjsGlobal$1 : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
        }, {}]
      }, {}, [1])(1);
    });
  });

  var browser = createCommonjsModule$1(function (module, exports) {

    var getGlobal = function () {
      // the only reliable means to get the global object is
      // `Function('return this')()`
      // However, this causes CSP violations in Chrome apps.
      if (typeof self !== 'undefined') {
        return self;
      }

      if (typeof window !== 'undefined') {
        return window;
      }

      if (typeof global !== 'undefined') {
        return global;
      }

      throw new Error('unable to locate global object');
    };

    var global = getGlobal();
    module.exports = exports = global.fetch; // Needed for TypeScript and Webpack.

    if (global.fetch) {
      exports.default = global.fetch.bind(global);
    }

    exports.Headers = global.Headers;
    exports.Request = global.Request;
    exports.Response = global.Response;
  });

  var fetchArrayBuffer = async function fetchArrayBufferBrowser(url) {
    const result = await browser(url);
    return result.arrayBuffer();
  };

  const loadingPromises$1 = {};

  var loadCommercials = async function loadCommercials(options = {}) {
    const {
      url = 'https://couch.cheminfo.org/cheminfo-public/d2eb480198c80275a1d05dd3609414f9/upload/commercials.zip'
    } = options;

    if (!loadingPromises$1[url]) {
      loadingPromises$1[url] = fetchArrayBuffer(url);
    }

    const buffer = await loadingPromises$1[url];
    const jsZip = new jszip();
    let zip = await jsZip.loadAsync(buffer);
    let fileData = await zip.files['commercials.json'].async('string');
    let data = JSON.parse(fileData);
    data.sort((a, b) => a.em - b.em);
    return data;
  };

  var constants = {
    ELECTRON_MASS: 5.4857990907e-4
  };

  /**
   * Define static variable corresponding to the various Kinds of a molecular formula part.
   */

  var Kind = {
    BEGIN: 'begin',
    ATOM: 'atom',
    MULTIPLIER_RANGE: 'multiplierRange',
    ISOTOPE: 'isotope',
    ISOTOPE_RATIO: 'isotopeRatio',
    CHARGE: 'charge',
    SALT: 'salt',
    OPENING_PARENTHESIS: 'openingParenthesis',
    CLOSING_PARENTHESIS: 'closingParenthesis',
    PRE_MULTIPLIER: 'preMultiplier',
    MULTIPLIER: 'multiplier',
    TEXT: 'text',
    ANCHOR: 'anchor',
    COMMENT: 'comment'
  };

  /**
   * Parse a string to extract the charge
   * The charge may be in the form --, +++, +3, -2, 4+, 2-
   * @param {*} charge
   */

  var parseCharge = function parseCharge(charge) {
    charge = charge.replace(/[()]/g, '');
    let chargeNumber = 0;

    if (charge.match(/^[+-]+$/)) {
      for (let i = 0; i < charge.length; i++) {
        if (charge.charAt(i) === '+') chargeNumber++;else chargeNumber--;
      }
    } else if (charge.match(/^[0-9]+[+-]$/)) {
      chargeNumber = Number(charge.charAt(charge.length - 1) + charge.substring(0, charge.length - 1));
    } else {
      chargeNumber = Number(charge);
    }

    return chargeNumber;
  };

  /**
   * Parse a mf to an array of kind / value
   * @param {String} mf
   */


  var parse = function parse(mf) {
    return new MFParser().parse(mf);
  };

  class MFParser {
    parse(mf = '') {
      this.mf = mf;
      this.i = 0;
      this.result = [];
      let lastKind = Kind.BEGIN;

      while (this.i < mf.length) {
        if (this.result.length > 0 && this.result[this.result.length - 1].kind !== Kind.TEXT) {
          lastKind = this.result[this.result.length - 1].kind;
        }

        let char = mf.charAt(this.i);
        let ascii = mf.charCodeAt(this.i);
        let nextAscii = 0;
        if (this.i + 1 < mf.length) nextAscii = mf.charCodeAt(this.i + 1);

        if (ascii > 47 && ascii < 58 || char === '-' && nextAscii > 47 && nextAscii < 58) {
          // a number
          let value = this.getNumber(ascii);

          if (lastKind === Kind.SALT || lastKind === Kind.BEGIN || lastKind === Kind.OPENING_PARENTHESIS) {
            if (value.to) {
              throw new MFError(this.mf, this.i, 'Premultiplier may not contain a -');
            }

            this.result.push({
              kind: Kind.PRE_MULTIPLIER,
              value: value.from
            });
          } else if (lastKind === Kind.ANCHOR) {
            if (value.to) {
              throw new MFError(this.mf, this.i, 'Anchor ID may not contain -');
            }

            this.result[this.result.length - 1].value = value.from;
          } else {
            if (value.to) {
              this.result.push({
                kind: Kind.MULTIPLIER_RANGE,
                value: {
                  from: Math.min(value.from, value.to),
                  to: Math.max(value.from, value.to)
                }
              });
            } else {
              this.result.push({
                kind: Kind.MULTIPLIER,
                value: value.from
              });
            }
          }

          continue;
        } else if (char === '.') {
          // a point
          this.result.push({
            kind: Kind.SALT,
            value: char
          }); // it is not in a number otherwise it would have been taken before
          // it must be in a salt
        } else if (char === '#') {
          // an anchor
          this.result.push({
            kind: Kind.ANCHOR,
            value: 0
          }); // it is not in a number otherwise it would have been taken before
          // it must be in a salt
        } else if (ascii > 64 && ascii < 91) {
          // an uppercase = new atom
          let value = this.getAtom(ascii);
          this.result.push({
            kind: Kind.ATOM,
            value
          });
          continue;
        } else if (ascii > 96 && ascii < 123) {
          // a lowercase
          throw new MFError(this.mf, this.i, 'found a lowercase not following an uppercase');
        } else if (char === '(') {
          let charge = this.getParenthesisCharge(ascii);

          if (charge) {
            this.result.push({
              kind: Kind.CHARGE,
              value: charge
            });
          } else {
            this.result.push({
              kind: Kind.OPENING_PARENTHESIS,
              value: '('
            });
          }
        } else if (char === ')') {
          this.result.push({
            kind: Kind.CLOSING_PARENTHESIS,
            value: ')'
          });
        } else if (char === '[') {
          // defines an isotope
          let isotope = this.getIsotope(ascii);
          this.result.push({
            kind: Kind.ISOTOPE,
            value: isotope
          });
        } else if (char === ']') {
          throw new MFError(this.mf, this.i, 'should never meet an closing bracket not in isotopes');
        } else if (char === '{') {
          // can define an exotic isotopic ratio or mixtures of groups
          let isotopeRatio = this.getCurlyBracketIsotopeRatio(ascii);

          if (lastKind === Kind.ATOM) {
            let lastResult = this.result[this.result.length - 1];
            lastResult.kind = Kind.ISOTOPE_RATIO;
            lastResult.value = {
              atom: lastResult.value,
              ratio: isotopeRatio
            };
          } else {
            throw new MFError(this.mf, this.i, 'isotopic composition has to follow an atom');
          }
        } else if (char === '}') {
          throw new MFError(this.mf, this.i, 'found a unexpected closing curly bracket');
        } else if (char === '+') {
          // charge not in parenthesis
          let charge = this.getNonParenthesisCharge(ascii);
          this.result.push({
            kind: Kind.CHARGE,
            value: charge
          });
        } else if (char === '-') {
          // charge not in parenthesis
          let charge = this.getNonParenthesisCharge(ascii);
          this.result.push({
            kind: Kind.CHARGE,
            value: charge
          });
        } else if (char === '$') {
          // it is a comment after
          this.result.push({
            kind: Kind.COMMENT,
            value: this.mf.substring(this.i + 1)
          });
          break;
        } else {
          this.result.push({
            kind: Kind.TEXT,
            value: char
          });
        }

        this.i++;
      }

      this.checkParenthesis();
      return this.result;
    }

    checkParenthesis() {
      let counter = 0;

      for (let line of this.result) {
        if (line.kind === Kind.OPENING_PARENTHESIS) counter++;
        if (line.kind === Kind.CLOSING_PARENTHESIS) counter--;
      }

      if (counter !== 0) {
        throw new MFError(this.mf, this.i, 'number of opening and closing parenthesis not equal');
      }
    }

    getNumber(ascii) {
      let number = '';
      let previous;

      do {
        previous = ascii;
        number += String.fromCharCode(ascii);
        this.i++;
        ascii = this.mf.charCodeAt(this.i);
      } while (ascii > 47 && ascii < 58 || ascii === 46 || ascii === 45 || ascii === 47); // number . - /
      // we need to deal with the case there is a from / to


      if (previous === 46) this.i--;
      let indexOfDash = number.indexOf('-', 1);

      if (indexOfDash > -1) {
        return {
          from: parseNumberWithDivision(number.substr(0, indexOfDash)),
          to: parseNumberWithDivision(number.substr(indexOfDash + 1))
        };
      }

      return {
        from: parseNumberWithDivision(number)
      };
    }

    getAtom(ascii) {
      let atom = '';

      do {
        atom += String.fromCharCode(ascii);
        this.i++;
        ascii = this.mf.charCodeAt(this.i);
      } while (ascii > 96 && ascii < 123);

      return atom;
    }

    getIsotope(ascii) {
      // [13C]
      let substring = '';

      do {
        substring += String.fromCharCode(ascii);
        this.i++;
        ascii = this.mf.charCodeAt(this.i);
      } while (ascii !== 93 && this.i <= this.mf.length);

      let atom = substring.replace(/[^a-zA-Z]/g, '');
      let isotope = Number(substring.replace(/[^0-9]/g, ''));
      return {
        atom,
        isotope
      };
    }

    getCurlyBracketIsotopeRatio(ascii) {
      let substring = '';
      let first = true;

      do {
        if (!first) {
          substring += String.fromCharCode(ascii);
        } else {
          first = false;
        }

        this.i++;
        ascii = this.mf.charCodeAt(this.i);
      } while (ascii !== 125 && this.i <= this.mf.length); // closing curly bracket


      if (substring.match(/^[0-9,]+$/)) {
        return substring.split(',').map(a => Number(a));
      }

      throw new MFError(this.mf, this.i, 'Curly brackets should contain only number and comma');
    }

    getParenthesisCharge(ascii) {
      let substring = '';
      let begin = this.i;

      do {
        substring += String.fromCharCode(ascii);
        this.i++;
        ascii = this.mf.charCodeAt(this.i);
      } while (ascii !== 41 && this.i <= this.mf.length); // closing parenthesis


      if (substring.match(/^\([0-9+-]+$/)) {
        return parseCharge(substring.substring(1));
      } else {
        this.i = begin;
        return undefined;
      }
    }

    getNonParenthesisCharge(ascii) {
      let substring = '';

      do {
        substring += String.fromCharCode(ascii);
        this.i++;
        ascii = this.mf.charCodeAt(this.i);
      } while (ascii === 43 || ascii === 45 || ascii > 47 && ascii < 58);

      this.i--;
      return parseCharge(substring);
    }

  }

  class MFError extends SyntaxError {
    constructor(mf, i, message) {
      let text = `${message}\n\n${mf}\n${' '.repeat(i)}^`;
      super(text);
    }

  }

  function parseNumberWithDivision(string) {
    if (string.includes('/')) {
      let parts = string.split('/');

      if (parts.length !== 2) {
        throw new TypeError('Can not parse MF with number like: ', string);
      }

      return Number(parts[0]) / Number(parts[1]);
    } else {
      return Number(string);
    }
  }

  /**
   * Defines static variables corresponding to the various formatting possibilities
   */

  var Format = {
    SUBSCRIPT: 'subscript',
    SUPERSCRIPT: 'superscript',
    SUPERIMPOSE: 'superimpose',
    TEXT: 'text'
  };

  var formatCharge = function formatCharge(charge) {
    if (charge === 1) return '+';
    if (charge > 1) return `+${charge}`;
    if (charge < 0) return String(charge);
    return '';
  };

  /**
   * Converts an array of mf elements to an array of formatting information
   * @param {Array<Object>} result of the parse method
   */


  var toDisplay = function convertForDisplay(lines) {
    let results = [];
    let result = {};

    for (let line of lines) {
      switch (line.kind) {
        case Kind.MULTIPLIER:
          if (line.value !== 1) {
            result = {
              kind: Format.SUBSCRIPT,
              value: String(line.value)
            };
            results.push(result);
          }

          break;

        case Kind.MULTIPLIER_RANGE:
          result = {
            kind: Format.SUBSCRIPT,
            value: `${String(line.value.from)}-${line.value.to}`
          };
          results.push(result);
          break;

        case Kind.CHARGE:
          if (result.kind === Format.SUBSCRIPT) {
            result.kind = Format.SUPERIMPOSE;
            result.over = formatCharge(line.value);
            result.under = result.value;
            result.value = undefined;
          } else {
            result = {
              kind: Format.SUPERSCRIPT,
              value: formatCharge(line.value)
            };
            results.push(result);
          }

          break;

        case Kind.ISOTOPE:
          result = {
            kind: Format.SUPERSCRIPT,
            value: line.value.isotope
          };
          results.push(result);
          result = {
            kind: Format.TEXT,
            value: line.value.atom
          };
          results.push(result);
          break;

        case Kind.ISOTOPE_RATIO:
          if (result.kind === Format.TEXT) {
            result.value += line.value.atom;
          } else {
            result = {
              kind: Format.TEXT,
              value: line.value.atom
            };
            results.push(result);
          }

          result = {
            kind: Format.SUPERSCRIPT,
            value: `{${line.value.ratio.join(',')}}`
          };
          results.push(result);
          break;

        case Kind.SALT:
          if (result.kind === Format.TEXT) {
            result.value += ' • ';
          } else {
            result = {
              kind: Format.TEXT,
              value: ' • '
            };
            results.push(result);
          }

          break;

        default:
          if (result.kind === Format.TEXT) {
            result.value += line.value;
          } else {
            result = {
              kind: Format.TEXT,
              value: line.value
            };
            results.push(result);
          }

      }
    }

    return results;
  };

  var Style$1 = {
    SUPERIMPOSE: 'flex-direction: column;display: inline-flex;justify-content: center;text-align: left;vertical-align: middle;',
    SUPERIMPOSE_SUP_SUB: 'line-height: 1; font-size: 70%'
  };

  var toHtml = function getHtml(lines) {
    let html = [];

    for (let line of lines) {
      switch (line.kind) {
        case Format.SUBSCRIPT:
          html.push(`<sub>${line.value}</sub>`);
          break;

        case Format.SUPERSCRIPT:
          html.push(`<sup>${line.value}</sup>`);
          break;

        case Format.SUPERIMPOSE:
          html.push(`<span style="${Style$1.SUPERIMPOSE}">`);
          html.push(`<sup style="${Style$1.SUPERIMPOSE_SUP_SUB}">${line.over}</sup>`);
          html.push(`<sub style="${Style$1.SUPERIMPOSE_SUP_SUB}">${line.under}</sub>`);
          html.push('</span>');
          break;

        default:
          html.push(line.value);
      }
    }

    return html.join('');
  };

  var elements$5 = [
  	{
  		number: 1,
  		isotopes: [
  			{
  				nominal: 1,
  				mass: 1.00782503223,
  				abundance: 0.999885
  			},
  			{
  				nominal: 2,
  				mass: 2.01410177812,
  				abundance: 0.000115
  			},
  			{
  				nominal: 3,
  				mass: 3.0160492779
  			},
  			{
  				nominal: 4,
  				mass: 4.02643
  			},
  			{
  				nominal: 5,
  				mass: 5.035311
  			},
  			{
  				nominal: 6,
  				mass: 6.04496
  			},
  			{
  				nominal: 7,
  				mass: 7.0527
  			}
  		],
  		symbol: "H",
  		mass: 1.0079407540557772,
  		name: "Hydrogen",
  		monoisotopicMass: 1.00782503223
  	},
  	{
  		number: 2,
  		isotopes: [
  			{
  				nominal: 3,
  				mass: 3.0160293201,
  				abundance: 0.00000134
  			},
  			{
  				nominal: 4,
  				mass: 4.00260325413,
  				abundance: 0.99999866
  			},
  			{
  				nominal: 5,
  				mass: 5.012057
  			},
  			{
  				nominal: 6,
  				mass: 6.018885891
  			},
  			{
  				nominal: 7,
  				mass: 7.0279907
  			},
  			{
  				nominal: 8,
  				mass: 8.03393439
  			},
  			{
  				nominal: 9,
  				mass: 9.043946
  			},
  			{
  				nominal: 10,
  				mass: 10.05279
  			}
  		],
  		symbol: "He",
  		mass: 4.002601932120929,
  		name: "Helium",
  		monoisotopicMass: 4.00260325413
  	},
  	{
  		number: 3,
  		isotopes: [
  			{
  				nominal: 3,
  				mass: 3.0308
  			},
  			{
  				nominal: 4,
  				mass: 4.02719
  			},
  			{
  				nominal: 5,
  				mass: 5.012538
  			},
  			{
  				nominal: 6,
  				mass: 6.0151228874,
  				abundance: 0.0759
  			},
  			{
  				nominal: 7,
  				mass: 7.0160034366,
  				abundance: 0.9241
  			},
  			{
  				nominal: 8,
  				mass: 8.022486246
  			},
  			{
  				nominal: 9,
  				mass: 9.02679019
  			},
  			{
  				nominal: 10,
  				mass: 10.035483
  			},
  			{
  				nominal: 11,
  				mass: 11.04372358
  			},
  			{
  				nominal: 12,
  				mass: 12.052517
  			},
  			{
  				nominal: 13,
  				mass: 13.06263
  			}
  		],
  		symbol: "Li",
  		mass: 6.94003660291572,
  		name: "Lithium",
  		monoisotopicMass: 7.0160034366
  	},
  	{
  		number: 4,
  		isotopes: [
  			{
  				nominal: 5,
  				mass: 5.0399
  			},
  			{
  				nominal: 6,
  				mass: 6.0197264
  			},
  			{
  				nominal: 7,
  				mass: 7.016928717
  			},
  			{
  				nominal: 8,
  				mass: 8.005305102
  			},
  			{
  				nominal: 9,
  				mass: 9.012183065,
  				abundance: 1
  			},
  			{
  				nominal: 10,
  				mass: 10.013534695
  			},
  			{
  				nominal: 11,
  				mass: 11.02166108
  			},
  			{
  				nominal: 12,
  				mass: 12.0269221
  			},
  			{
  				nominal: 13,
  				mass: 13.036135
  			},
  			{
  				nominal: 14,
  				mass: 14.04289
  			},
  			{
  				nominal: 15,
  				mass: 15.05342
  			},
  			{
  				nominal: 16,
  				mass: 16.06167
  			}
  		],
  		symbol: "Be",
  		mass: 9.012183065,
  		name: "Beryllium",
  		monoisotopicMass: 9.012183065
  	},
  	{
  		number: 5,
  		isotopes: [
  			{
  				nominal: 6,
  				mass: 6.0508
  			},
  			{
  				nominal: 7,
  				mass: 7.029712
  			},
  			{
  				nominal: 8,
  				mass: 8.0246073
  			},
  			{
  				nominal: 9,
  				mass: 9.01332965
  			},
  			{
  				nominal: 10,
  				mass: 10.01293695,
  				abundance: 0.199
  			},
  			{
  				nominal: 11,
  				mass: 11.00930536,
  				abundance: 0.801
  			},
  			{
  				nominal: 12,
  				mass: 12.0143527
  			},
  			{
  				nominal: 13,
  				mass: 13.0177802
  			},
  			{
  				nominal: 14,
  				mass: 14.025404
  			},
  			{
  				nominal: 15,
  				mass: 15.031088
  			},
  			{
  				nominal: 16,
  				mass: 16.039842
  			},
  			{
  				nominal: 17,
  				mass: 17.04699
  			},
  			{
  				nominal: 18,
  				mass: 18.05566
  			},
  			{
  				nominal: 19,
  				mass: 19.0631
  			},
  			{
  				nominal: 20,
  				mass: 20.07207
  			},
  			{
  				nominal: 21,
  				mass: 21.08129
  			}
  		],
  		symbol: "B",
  		mass: 10.811028046410001,
  		name: "Boron",
  		monoisotopicMass: 11.00930536
  	},
  	{
  		number: 6,
  		isotopes: [
  			{
  				nominal: 8,
  				mass: 8.037643
  			},
  			{
  				nominal: 9,
  				mass: 9.0310372
  			},
  			{
  				nominal: 10,
  				mass: 10.01685331
  			},
  			{
  				nominal: 11,
  				mass: 11.0114336
  			},
  			{
  				nominal: 12,
  				mass: 12,
  				abundance: 0.9893
  			},
  			{
  				nominal: 13,
  				mass: 13.00335483507,
  				abundance: 0.0107
  			},
  			{
  				nominal: 14,
  				mass: 14.0032419884
  			},
  			{
  				nominal: 15,
  				mass: 15.01059926
  			},
  			{
  				nominal: 16,
  				mass: 16.0147013
  			},
  			{
  				nominal: 17,
  				mass: 17.022577
  			},
  			{
  				nominal: 18,
  				mass: 18.026751
  			},
  			{
  				nominal: 19,
  				mass: 19.0348
  			},
  			{
  				nominal: 20,
  				mass: 20.04032
  			},
  			{
  				nominal: 21,
  				mass: 21.049
  			},
  			{
  				nominal: 22,
  				mass: 22.05753
  			},
  			{
  				nominal: 23,
  				mass: 23.0689
  			}
  		],
  		symbol: "C",
  		mass: 12.010735896735248,
  		name: "Carbon",
  		monoisotopicMass: 12
  	},
  	{
  		number: 7,
  		isotopes: [
  			{
  				nominal: 10,
  				mass: 10.04165
  			},
  			{
  				nominal: 11,
  				mass: 11.026091
  			},
  			{
  				nominal: 12,
  				mass: 12.0186132
  			},
  			{
  				nominal: 13,
  				mass: 13.00573861
  			},
  			{
  				nominal: 14,
  				mass: 14.00307400443,
  				abundance: 0.99636
  			},
  			{
  				nominal: 15,
  				mass: 15.00010889888,
  				abundance: 0.00364
  			},
  			{
  				nominal: 16,
  				mass: 16.0061019
  			},
  			{
  				nominal: 17,
  				mass: 17.008449
  			},
  			{
  				nominal: 18,
  				mass: 18.014078
  			},
  			{
  				nominal: 19,
  				mass: 19.017022
  			},
  			{
  				nominal: 20,
  				mass: 20.023366
  			},
  			{
  				nominal: 21,
  				mass: 21.02711
  			},
  			{
  				nominal: 22,
  				mass: 22.03439
  			},
  			{
  				nominal: 23,
  				mass: 23.04114
  			},
  			{
  				nominal: 24,
  				mass: 24.05039
  			},
  			{
  				nominal: 25,
  				mass: 25.0601
  			}
  		],
  		symbol: "N",
  		mass: 14.006703211445798,
  		name: "Nitrogen",
  		monoisotopicMass: 14.00307400443
  	},
  	{
  		number: 8,
  		isotopes: [
  			{
  				nominal: 12,
  				mass: 12.034262
  			},
  			{
  				nominal: 13,
  				mass: 13.024815
  			},
  			{
  				nominal: 14,
  				mass: 14.00859636
  			},
  			{
  				nominal: 15,
  				mass: 15.00306562
  			},
  			{
  				nominal: 16,
  				mass: 15.99491461957,
  				abundance: 0.99757
  			},
  			{
  				nominal: 17,
  				mass: 16.9991317565,
  				abundance: 0.00038
  			},
  			{
  				nominal: 18,
  				mass: 17.99915961286,
  				abundance: 0.00205
  			},
  			{
  				nominal: 19,
  				mass: 19.003578
  			},
  			{
  				nominal: 20,
  				mass: 20.00407535
  			},
  			{
  				nominal: 21,
  				mass: 21.008655
  			},
  			{
  				nominal: 22,
  				mass: 22.009966
  			},
  			{
  				nominal: 23,
  				mass: 23.015696
  			},
  			{
  				nominal: 24,
  				mass: 24.01986
  			},
  			{
  				nominal: 25,
  				mass: 25.02936
  			},
  			{
  				nominal: 26,
  				mass: 26.03729
  			},
  			{
  				nominal: 27,
  				mass: 27.04772
  			},
  			{
  				nominal: 28,
  				mass: 28.05591
  			}
  		],
  		symbol: "O",
  		mass: 15.999404924318277,
  		name: "Oxygen",
  		monoisotopicMass: 15.99491461957
  	},
  	{
  		number: 9,
  		isotopes: [
  			{
  				nominal: 14,
  				mass: 14.034315
  			},
  			{
  				nominal: 15,
  				mass: 15.018043
  			},
  			{
  				nominal: 16,
  				mass: 16.0114657
  			},
  			{
  				nominal: 17,
  				mass: 17.00209524
  			},
  			{
  				nominal: 18,
  				mass: 18.00093733
  			},
  			{
  				nominal: 19,
  				mass: 18.99840316273,
  				abundance: 1
  			},
  			{
  				nominal: 20,
  				mass: 19.999981252
  			},
  			{
  				nominal: 21,
  				mass: 20.9999489
  			},
  			{
  				nominal: 22,
  				mass: 22.002999
  			},
  			{
  				nominal: 23,
  				mass: 23.003557
  			},
  			{
  				nominal: 24,
  				mass: 24.008115
  			},
  			{
  				nominal: 25,
  				mass: 25.012199
  			},
  			{
  				nominal: 26,
  				mass: 26.020038
  			},
  			{
  				nominal: 27,
  				mass: 27.02644
  			},
  			{
  				nominal: 28,
  				mass: 28.03534
  			},
  			{
  				nominal: 29,
  				mass: 29.04254
  			},
  			{
  				nominal: 30,
  				mass: 30.05165
  			},
  			{
  				nominal: 31,
  				mass: 31.05971
  			}
  		],
  		symbol: "F",
  		mass: 18.99840316273,
  		name: "Fluorine",
  		monoisotopicMass: 18.99840316273
  	},
  	{
  		number: 10,
  		isotopes: [
  			{
  				nominal: 16,
  				mass: 16.02575
  			},
  			{
  				nominal: 17,
  				mass: 17.01771396
  			},
  			{
  				nominal: 18,
  				mass: 18.0057087
  			},
  			{
  				nominal: 19,
  				mass: 19.00188091
  			},
  			{
  				nominal: 20,
  				mass: 19.9924401762,
  				abundance: 0.9048
  			},
  			{
  				nominal: 21,
  				mass: 20.993846685,
  				abundance: 0.0027
  			},
  			{
  				nominal: 22,
  				mass: 21.991385114,
  				abundance: 0.0925
  			},
  			{
  				nominal: 23,
  				mass: 22.99446691
  			},
  			{
  				nominal: 24,
  				mass: 23.99361065
  			},
  			{
  				nominal: 25,
  				mass: 24.997789
  			},
  			{
  				nominal: 26,
  				mass: 26.000515
  			},
  			{
  				nominal: 27,
  				mass: 27.007553
  			},
  			{
  				nominal: 28,
  				mass: 28.01212
  			},
  			{
  				nominal: 29,
  				mass: 29.01975
  			},
  			{
  				nominal: 30,
  				mass: 30.02473
  			},
  			{
  				nominal: 31,
  				mass: 31.0331
  			},
  			{
  				nominal: 32,
  				mass: 32.03972
  			},
  			{
  				nominal: 33,
  				mass: 33.04938
  			},
  			{
  				nominal: 34,
  				mass: 34.05673
  			}
  		],
  		symbol: "Ne",
  		mass: 20.18004638052026,
  		name: "Neon",
  		monoisotopicMass: 19.9924401762
  	},
  	{
  		number: 11,
  		isotopes: [
  			{
  				nominal: 18,
  				mass: 18.02688
  			},
  			{
  				nominal: 19,
  				mass: 19.01388
  			},
  			{
  				nominal: 20,
  				mass: 20.0073544
  			},
  			{
  				nominal: 21,
  				mass: 20.99765469
  			},
  			{
  				nominal: 22,
  				mass: 21.99443741
  			},
  			{
  				nominal: 23,
  				mass: 22.989769282,
  				abundance: 1
  			},
  			{
  				nominal: 24,
  				mass: 23.99096295
  			},
  			{
  				nominal: 25,
  				mass: 24.989954
  			},
  			{
  				nominal: 26,
  				mass: 25.9926346
  			},
  			{
  				nominal: 27,
  				mass: 26.9940765
  			},
  			{
  				nominal: 28,
  				mass: 27.998939
  			},
  			{
  				nominal: 29,
  				mass: 29.0028771
  			},
  			{
  				nominal: 30,
  				mass: 30.0090979
  			},
  			{
  				nominal: 31,
  				mass: 31.013163
  			},
  			{
  				nominal: 32,
  				mass: 32.02019
  			},
  			{
  				nominal: 33,
  				mass: 33.02573
  			},
  			{
  				nominal: 34,
  				mass: 34.03359
  			},
  			{
  				nominal: 35,
  				mass: 35.04062
  			},
  			{
  				nominal: 36,
  				mass: 36.04929
  			},
  			{
  				nominal: 37,
  				mass: 37.05705
  			}
  		],
  		symbol: "Na",
  		mass: 22.989769282,
  		name: "Sodium",
  		monoisotopicMass: 22.989769282
  	},
  	{
  		number: 12,
  		isotopes: [
  			{
  				nominal: 19,
  				mass: 19.034169
  			},
  			{
  				nominal: 20,
  				mass: 20.01885
  			},
  			{
  				nominal: 21,
  				mass: 21.011716
  			},
  			{
  				nominal: 22,
  				mass: 21.99957065
  			},
  			{
  				nominal: 23,
  				mass: 22.99412421
  			},
  			{
  				nominal: 24,
  				mass: 23.985041697,
  				abundance: 0.7899
  			},
  			{
  				nominal: 25,
  				mass: 24.985836976,
  				abundance: 0.1
  			},
  			{
  				nominal: 26,
  				mass: 25.982592968,
  				abundance: 0.1101
  			},
  			{
  				nominal: 27,
  				mass: 26.984340624
  			},
  			{
  				nominal: 28,
  				mass: 27.9838767
  			},
  			{
  				nominal: 29,
  				mass: 28.988617
  			},
  			{
  				nominal: 30,
  				mass: 29.9904629
  			},
  			{
  				nominal: 31,
  				mass: 30.996648
  			},
  			{
  				nominal: 32,
  				mass: 31.9991102
  			},
  			{
  				nominal: 33,
  				mass: 33.0053271
  			},
  			{
  				nominal: 34,
  				mass: 34.008935
  			},
  			{
  				nominal: 35,
  				mass: 35.01679
  			},
  			{
  				nominal: 36,
  				mass: 36.02188
  			},
  			{
  				nominal: 37,
  				mass: 37.03037
  			},
  			{
  				nominal: 38,
  				mass: 38.03658
  			},
  			{
  				nominal: 39,
  				mass: 39.04538
  			},
  			{
  				nominal: 40,
  				mass: 40.05218
  			}
  		],
  		symbol: "Mg",
  		mass: 24.3050516198371,
  		name: "Magnesium",
  		monoisotopicMass: 23.985041697
  	},
  	{
  		number: 13,
  		isotopes: [
  			{
  				nominal: 21,
  				mass: 21.02897
  			},
  			{
  				nominal: 22,
  				mass: 22.01954
  			},
  			{
  				nominal: 23,
  				mass: 23.00724435
  			},
  			{
  				nominal: 24,
  				mass: 23.9999489
  			},
  			{
  				nominal: 25,
  				mass: 24.9904281
  			},
  			{
  				nominal: 26,
  				mass: 25.986891904
  			},
  			{
  				nominal: 27,
  				mass: 26.98153853,
  				abundance: 1
  			},
  			{
  				nominal: 28,
  				mass: 27.98191021
  			},
  			{
  				nominal: 29,
  				mass: 28.9804565
  			},
  			{
  				nominal: 30,
  				mass: 29.98296
  			},
  			{
  				nominal: 31,
  				mass: 30.983945
  			},
  			{
  				nominal: 32,
  				mass: 31.988085
  			},
  			{
  				nominal: 33,
  				mass: 32.990909
  			},
  			{
  				nominal: 34,
  				mass: 33.996705
  			},
  			{
  				nominal: 35,
  				mass: 34.999764
  			},
  			{
  				nominal: 36,
  				mass: 36.00639
  			},
  			{
  				nominal: 37,
  				mass: 37.01053
  			},
  			{
  				nominal: 38,
  				mass: 38.0174
  			},
  			{
  				nominal: 39,
  				mass: 39.02254
  			},
  			{
  				nominal: 40,
  				mass: 40.03003
  			},
  			{
  				nominal: 41,
  				mass: 41.03638
  			},
  			{
  				nominal: 42,
  				mass: 42.04384
  			},
  			{
  				nominal: 43,
  				mass: 43.05147
  			}
  		],
  		symbol: "Al",
  		mass: 26.98153853,
  		name: "Aluminium",
  		monoisotopicMass: 26.98153853
  	},
  	{
  		number: 14,
  		isotopes: [
  			{
  				nominal: 22,
  				mass: 22.03579
  			},
  			{
  				nominal: 23,
  				mass: 23.02544
  			},
  			{
  				nominal: 24,
  				mass: 24.011535
  			},
  			{
  				nominal: 25,
  				mass: 25.004109
  			},
  			{
  				nominal: 26,
  				mass: 25.99233384
  			},
  			{
  				nominal: 27,
  				mass: 26.98670481
  			},
  			{
  				nominal: 28,
  				mass: 27.97692653465,
  				abundance: 0.92223
  			},
  			{
  				nominal: 29,
  				mass: 28.9764946649,
  				abundance: 0.04685
  			},
  			{
  				nominal: 30,
  				mass: 29.973770136,
  				abundance: 0.03092
  			},
  			{
  				nominal: 31,
  				mass: 30.975363194
  			},
  			{
  				nominal: 32,
  				mass: 31.97415154
  			},
  			{
  				nominal: 33,
  				mass: 32.97797696
  			},
  			{
  				nominal: 34,
  				mass: 33.978576
  			},
  			{
  				nominal: 35,
  				mass: 34.984583
  			},
  			{
  				nominal: 36,
  				mass: 35.986695
  			},
  			{
  				nominal: 37,
  				mass: 36.992921
  			},
  			{
  				nominal: 38,
  				mass: 37.995523
  			},
  			{
  				nominal: 39,
  				mass: 39.002491
  			},
  			{
  				nominal: 40,
  				mass: 40.00583
  			},
  			{
  				nominal: 41,
  				mass: 41.01301
  			},
  			{
  				nominal: 42,
  				mass: 42.01778
  			},
  			{
  				nominal: 43,
  				mass: 43.0248
  			},
  			{
  				nominal: 44,
  				mass: 44.03061
  			},
  			{
  				nominal: 45,
  				mass: 45.03995
  			}
  		],
  		symbol: "Si",
  		mass: 28.085498705705955,
  		name: "Silicon",
  		monoisotopicMass: 27.97692653465
  	},
  	{
  		number: 15,
  		isotopes: [
  			{
  				nominal: 24,
  				mass: 24.03577
  			},
  			{
  				nominal: 25,
  				mass: 25.02119
  			},
  			{
  				nominal: 26,
  				mass: 26.01178
  			},
  			{
  				nominal: 27,
  				mass: 26.999224
  			},
  			{
  				nominal: 28,
  				mass: 27.9923266
  			},
  			{
  				nominal: 29,
  				mass: 28.98180079
  			},
  			{
  				nominal: 30,
  				mass: 29.97831375
  			},
  			{
  				nominal: 31,
  				mass: 30.97376199842,
  				abundance: 1
  			},
  			{
  				nominal: 32,
  				mass: 31.973907643
  			},
  			{
  				nominal: 33,
  				mass: 32.9717257
  			},
  			{
  				nominal: 34,
  				mass: 33.97364589
  			},
  			{
  				nominal: 35,
  				mass: 34.9733141
  			},
  			{
  				nominal: 36,
  				mass: 35.97826
  			},
  			{
  				nominal: 37,
  				mass: 36.979607
  			},
  			{
  				nominal: 38,
  				mass: 37.984252
  			},
  			{
  				nominal: 39,
  				mass: 38.986227
  			},
  			{
  				nominal: 40,
  				mass: 39.99133
  			},
  			{
  				nominal: 41,
  				mass: 40.994654
  			},
  			{
  				nominal: 42,
  				mass: 42.00108
  			},
  			{
  				nominal: 43,
  				mass: 43.00502
  			},
  			{
  				nominal: 44,
  				mass: 44.01121
  			},
  			{
  				nominal: 45,
  				mass: 45.01645
  			},
  			{
  				nominal: 46,
  				mass: 46.02446
  			},
  			{
  				nominal: 47,
  				mass: 47.03139
  			}
  		],
  		symbol: "P",
  		mass: 30.97376199842,
  		name: "Phosphorus",
  		monoisotopicMass: 30.97376199842
  	},
  	{
  		number: 16,
  		isotopes: [
  			{
  				nominal: 26,
  				mass: 26.02907
  			},
  			{
  				nominal: 27,
  				mass: 27.01828
  			},
  			{
  				nominal: 28,
  				mass: 28.00437
  			},
  			{
  				nominal: 29,
  				mass: 28.996611
  			},
  			{
  				nominal: 30,
  				mass: 29.98490703
  			},
  			{
  				nominal: 31,
  				mass: 30.97955701
  			},
  			{
  				nominal: 32,
  				mass: 31.9720711744,
  				abundance: 0.9499
  			},
  			{
  				nominal: 33,
  				mass: 32.9714589098,
  				abundance: 0.0075
  			},
  			{
  				nominal: 34,
  				mass: 33.967867004,
  				abundance: 0.0425
  			},
  			{
  				nominal: 35,
  				mass: 34.96903231
  			},
  			{
  				nominal: 36,
  				mass: 35.96708071,
  				abundance: 0.0001
  			},
  			{
  				nominal: 37,
  				mass: 36.97112551
  			},
  			{
  				nominal: 38,
  				mass: 37.9711633
  			},
  			{
  				nominal: 39,
  				mass: 38.975134
  			},
  			{
  				nominal: 40,
  				mass: 39.9754826
  			},
  			{
  				nominal: 41,
  				mass: 40.9795935
  			},
  			{
  				nominal: 42,
  				mass: 41.9810651
  			},
  			{
  				nominal: 43,
  				mass: 42.9869076
  			},
  			{
  				nominal: 44,
  				mass: 43.9901188
  			},
  			{
  				nominal: 45,
  				mass: 44.99572
  			},
  			{
  				nominal: 46,
  				mass: 46.00004
  			},
  			{
  				nominal: 47,
  				mass: 47.00795
  			},
  			{
  				nominal: 48,
  				mass: 48.0137
  			},
  			{
  				nominal: 49,
  				mass: 49.02276
  			}
  		],
  		symbol: "S",
  		mass: 32.06478740612706,
  		name: "Sulfur",
  		monoisotopicMass: 31.9720711744
  	},
  	{
  		number: 17,
  		isotopes: [
  			{
  				nominal: 28,
  				mass: 28.02954
  			},
  			{
  				nominal: 29,
  				mass: 29.01478
  			},
  			{
  				nominal: 30,
  				mass: 30.00477
  			},
  			{
  				nominal: 31,
  				mass: 30.992414
  			},
  			{
  				nominal: 32,
  				mass: 31.98568464
  			},
  			{
  				nominal: 33,
  				mass: 32.97745199
  			},
  			{
  				nominal: 34,
  				mass: 33.973762485
  			},
  			{
  				nominal: 35,
  				mass: 34.968852682,
  				abundance: 0.7576
  			},
  			{
  				nominal: 36,
  				mass: 35.968306809
  			},
  			{
  				nominal: 37,
  				mass: 36.965902602,
  				abundance: 0.2424
  			},
  			{
  				nominal: 38,
  				mass: 37.96801044
  			},
  			{
  				nominal: 39,
  				mass: 38.9680082
  			},
  			{
  				nominal: 40,
  				mass: 39.970415
  			},
  			{
  				nominal: 41,
  				mass: 40.970685
  			},
  			{
  				nominal: 42,
  				mass: 41.97325
  			},
  			{
  				nominal: 43,
  				mass: 42.97389
  			},
  			{
  				nominal: 44,
  				mass: 43.97787
  			},
  			{
  				nominal: 45,
  				mass: 44.98029
  			},
  			{
  				nominal: 46,
  				mass: 45.98517
  			},
  			{
  				nominal: 47,
  				mass: 46.98916
  			},
  			{
  				nominal: 48,
  				mass: 47.99564
  			},
  			{
  				nominal: 49,
  				mass: 49.00123
  			},
  			{
  				nominal: 50,
  				mass: 50.00905
  			},
  			{
  				nominal: 51,
  				mass: 51.01554
  			}
  		],
  		symbol: "Cl",
  		mass: 35.452937582608,
  		name: "Chlorine",
  		monoisotopicMass: 34.968852682
  	},
  	{
  		number: 18,
  		isotopes: [
  			{
  				nominal: 30,
  				mass: 30.02307
  			},
  			{
  				nominal: 31,
  				mass: 31.01212
  			},
  			{
  				nominal: 32,
  				mass: 31.9976378
  			},
  			{
  				nominal: 33,
  				mass: 32.98992555
  			},
  			{
  				nominal: 34,
  				mass: 33.98027009
  			},
  			{
  				nominal: 35,
  				mass: 34.97525759
  			},
  			{
  				nominal: 36,
  				mass: 35.967545105,
  				abundance: 0.003336
  			},
  			{
  				nominal: 37,
  				mass: 36.96677633
  			},
  			{
  				nominal: 38,
  				mass: 37.96273211,
  				abundance: 0.000629
  			},
  			{
  				nominal: 39,
  				mass: 38.964313
  			},
  			{
  				nominal: 40,
  				mass: 39.9623831237,
  				abundance: 0.996035
  			},
  			{
  				nominal: 41,
  				mass: 40.96450057
  			},
  			{
  				nominal: 42,
  				mass: 41.9630457
  			},
  			{
  				nominal: 43,
  				mass: 42.9656361
  			},
  			{
  				nominal: 44,
  				mass: 43.9649238
  			},
  			{
  				nominal: 45,
  				mass: 44.96803973
  			},
  			{
  				nominal: 46,
  				mass: 45.968083
  			},
  			{
  				nominal: 47,
  				mass: 46.972935
  			},
  			{
  				nominal: 48,
  				mass: 47.97591
  			},
  			{
  				nominal: 49,
  				mass: 48.9819
  			},
  			{
  				nominal: 50,
  				mass: 49.98613
  			},
  			{
  				nominal: 51,
  				mass: 50.9937
  			},
  			{
  				nominal: 52,
  				mass: 51.99896
  			},
  			{
  				nominal: 53,
  				mass: 53.00729
  			}
  		],
  		symbol: "Ar",
  		mass: 39.947798563582005,
  		name: "Argon",
  		monoisotopicMass: 39.9623831237
  	},
  	{
  		number: 19,
  		isotopes: [
  			{
  				nominal: 32,
  				mass: 32.02265
  			},
  			{
  				nominal: 33,
  				mass: 33.00756
  			},
  			{
  				nominal: 34,
  				mass: 33.99869
  			},
  			{
  				nominal: 35,
  				mass: 34.98800541
  			},
  			{
  				nominal: 36,
  				mass: 35.98130201
  			},
  			{
  				nominal: 37,
  				mass: 36.97337589
  			},
  			{
  				nominal: 38,
  				mass: 37.96908112
  			},
  			{
  				nominal: 39,
  				mass: 38.9637064864,
  				abundance: 0.932581
  			},
  			{
  				nominal: 40,
  				mass: 39.963998166,
  				abundance: 0.000117
  			},
  			{
  				nominal: 41,
  				mass: 40.9618252579,
  				abundance: 0.067302
  			},
  			{
  				nominal: 42,
  				mass: 41.96240231
  			},
  			{
  				nominal: 43,
  				mass: 42.9607347
  			},
  			{
  				nominal: 44,
  				mass: 43.96158699
  			},
  			{
  				nominal: 45,
  				mass: 44.96069149
  			},
  			{
  				nominal: 46,
  				mass: 45.96198159
  			},
  			{
  				nominal: 47,
  				mass: 46.9616616
  			},
  			{
  				nominal: 48,
  				mass: 47.96534119
  			},
  			{
  				nominal: 49,
  				mass: 48.96821075
  			},
  			{
  				nominal: 50,
  				mass: 49.97238
  			},
  			{
  				nominal: 51,
  				mass: 50.975828
  			},
  			{
  				nominal: 52,
  				mass: 51.98224
  			},
  			{
  				nominal: 53,
  				mass: 52.98746
  			},
  			{
  				nominal: 54,
  				mass: 53.99463
  			},
  			{
  				nominal: 55,
  				mass: 55.00076
  			},
  			{
  				nominal: 56,
  				mass: 56.00851
  			}
  		],
  		symbol: "K",
  		mass: 39.098300910086,
  		name: "Potassium",
  		monoisotopicMass: 38.9637064864
  	},
  	{
  		number: 20,
  		isotopes: [
  			{
  				nominal: 34,
  				mass: 34.01487
  			},
  			{
  				nominal: 35,
  				mass: 35.00514
  			},
  			{
  				nominal: 36,
  				mass: 35.993074
  			},
  			{
  				nominal: 37,
  				mass: 36.98589785
  			},
  			{
  				nominal: 38,
  				mass: 37.97631922
  			},
  			{
  				nominal: 39,
  				mass: 38.97071081
  			},
  			{
  				nominal: 40,
  				mass: 39.962590863,
  				abundance: 0.96941
  			},
  			{
  				nominal: 41,
  				mass: 40.96227792
  			},
  			{
  				nominal: 42,
  				mass: 41.95861783,
  				abundance: 0.00647
  			},
  			{
  				nominal: 43,
  				mass: 42.95876644,
  				abundance: 0.00135
  			},
  			{
  				nominal: 44,
  				mass: 43.95548156,
  				abundance: 0.02086
  			},
  			{
  				nominal: 45,
  				mass: 44.95618635
  			},
  			{
  				nominal: 46,
  				mass: 45.953689,
  				abundance: 0.00004
  			},
  			{
  				nominal: 47,
  				mass: 46.9545424
  			},
  			{
  				nominal: 48,
  				mass: 47.95252276,
  				abundance: 0.00187
  			},
  			{
  				nominal: 49,
  				mass: 48.95566274
  			},
  			{
  				nominal: 50,
  				mass: 49.9574992
  			},
  			{
  				nominal: 51,
  				mass: 50.960989
  			},
  			{
  				nominal: 52,
  				mass: 51.963217
  			},
  			{
  				nominal: 53,
  				mass: 52.96945
  			},
  			{
  				nominal: 54,
  				mass: 53.9734
  			},
  			{
  				nominal: 55,
  				mass: 54.9803
  			},
  			{
  				nominal: 56,
  				mass: 55.98508
  			},
  			{
  				nominal: 57,
  				mass: 56.99262
  			},
  			{
  				nominal: 58,
  				mass: 57.99794
  			}
  		],
  		symbol: "Ca",
  		mass: 40.078022511017735,
  		name: "Calcium",
  		monoisotopicMass: 39.962590863
  	},
  	{
  		number: 21,
  		isotopes: [
  			{
  				nominal: 36,
  				mass: 36.01648
  			},
  			{
  				nominal: 37,
  				mass: 37.00374
  			},
  			{
  				nominal: 38,
  				mass: 37.99512
  			},
  			{
  				nominal: 39,
  				mass: 38.984785
  			},
  			{
  				nominal: 40,
  				mass: 39.9779673
  			},
  			{
  				nominal: 41,
  				mass: 40.969251105
  			},
  			{
  				nominal: 42,
  				mass: 41.96551653
  			},
  			{
  				nominal: 43,
  				mass: 42.9611505
  			},
  			{
  				nominal: 44,
  				mass: 43.9594029
  			},
  			{
  				nominal: 45,
  				mass: 44.95590828,
  				abundance: 1
  			},
  			{
  				nominal: 46,
  				mass: 45.95516826
  			},
  			{
  				nominal: 47,
  				mass: 46.9524037
  			},
  			{
  				nominal: 48,
  				mass: 47.9522236
  			},
  			{
  				nominal: 49,
  				mass: 48.9500146
  			},
  			{
  				nominal: 50,
  				mass: 49.952176
  			},
  			{
  				nominal: 51,
  				mass: 50.953592
  			},
  			{
  				nominal: 52,
  				mass: 51.95688
  			},
  			{
  				nominal: 53,
  				mass: 52.95909
  			},
  			{
  				nominal: 54,
  				mass: 53.96393
  			},
  			{
  				nominal: 55,
  				mass: 54.96782
  			},
  			{
  				nominal: 56,
  				mass: 55.97345
  			},
  			{
  				nominal: 57,
  				mass: 56.97777
  			},
  			{
  				nominal: 58,
  				mass: 57.98403
  			},
  			{
  				nominal: 59,
  				mass: 58.98894
  			},
  			{
  				nominal: 60,
  				mass: 59.99565
  			},
  			{
  				nominal: 61,
  				mass: 61.001
  			}
  		],
  		symbol: "Sc",
  		mass: 44.95590828,
  		name: "Scandium",
  		monoisotopicMass: 44.95590828
  	},
  	{
  		number: 22,
  		isotopes: [
  			{
  				nominal: 38,
  				mass: 38.01145
  			},
  			{
  				nominal: 39,
  				mass: 39.00236
  			},
  			{
  				nominal: 40,
  				mass: 39.9905
  			},
  			{
  				nominal: 41,
  				mass: 40.983148
  			},
  			{
  				nominal: 42,
  				mass: 41.97304903
  			},
  			{
  				nominal: 43,
  				mass: 42.9685225
  			},
  			{
  				nominal: 44,
  				mass: 43.95968995
  			},
  			{
  				nominal: 45,
  				mass: 44.95812198
  			},
  			{
  				nominal: 46,
  				mass: 45.95262772,
  				abundance: 0.0825
  			},
  			{
  				nominal: 47,
  				mass: 46.95175879,
  				abundance: 0.0744
  			},
  			{
  				nominal: 48,
  				mass: 47.94794198,
  				abundance: 0.7372
  			},
  			{
  				nominal: 49,
  				mass: 48.94786568,
  				abundance: 0.0541
  			},
  			{
  				nominal: 50,
  				mass: 49.94478689,
  				abundance: 0.0518
  			},
  			{
  				nominal: 51,
  				mass: 50.94661065
  			},
  			{
  				nominal: 52,
  				mass: 51.946893
  			},
  			{
  				nominal: 53,
  				mass: 52.94973
  			},
  			{
  				nominal: 54,
  				mass: 53.95105
  			},
  			{
  				nominal: 55,
  				mass: 54.95527
  			},
  			{
  				nominal: 56,
  				mass: 55.95791
  			},
  			{
  				nominal: 57,
  				mass: 56.96364
  			},
  			{
  				nominal: 58,
  				mass: 57.9666
  			},
  			{
  				nominal: 59,
  				mass: 58.97247
  			},
  			{
  				nominal: 60,
  				mass: 59.97603
  			},
  			{
  				nominal: 61,
  				mass: 60.98245
  			},
  			{
  				nominal: 62,
  				mass: 61.98651
  			},
  			{
  				nominal: 63,
  				mass: 62.99375
  			}
  		],
  		symbol: "Ti",
  		mass: 47.866744962721995,
  		name: "Titanium",
  		monoisotopicMass: 47.94794198
  	},
  	{
  		number: 23,
  		isotopes: [
  			{
  				nominal: 40,
  				mass: 40.01276
  			},
  			{
  				nominal: 41,
  				mass: 41.00021
  			},
  			{
  				nominal: 42,
  				mass: 41.99182
  			},
  			{
  				nominal: 43,
  				mass: 42.980766
  			},
  			{
  				nominal: 44,
  				mass: 43.97411
  			},
  			{
  				nominal: 45,
  				mass: 44.9657748
  			},
  			{
  				nominal: 46,
  				mass: 45.96019878
  			},
  			{
  				nominal: 47,
  				mass: 46.95490491
  			},
  			{
  				nominal: 48,
  				mass: 47.9522522
  			},
  			{
  				nominal: 49,
  				mass: 48.9485118
  			},
  			{
  				nominal: 50,
  				mass: 49.94715601,
  				abundance: 0.0025
  			},
  			{
  				nominal: 51,
  				mass: 50.94395704,
  				abundance: 0.9975
  			},
  			{
  				nominal: 52,
  				mass: 51.94477301
  			},
  			{
  				nominal: 53,
  				mass: 52.9443367
  			},
  			{
  				nominal: 54,
  				mass: 53.946439
  			},
  			{
  				nominal: 55,
  				mass: 54.94724
  			},
  			{
  				nominal: 56,
  				mass: 55.95048
  			},
  			{
  				nominal: 57,
  				mass: 56.95252
  			},
  			{
  				nominal: 58,
  				mass: 57.95672
  			},
  			{
  				nominal: 59,
  				mass: 58.95939
  			},
  			{
  				nominal: 60,
  				mass: 59.96431
  			},
  			{
  				nominal: 61,
  				mass: 60.96725
  			},
  			{
  				nominal: 62,
  				mass: 61.97265
  			},
  			{
  				nominal: 63,
  				mass: 62.97639
  			},
  			{
  				nominal: 64,
  				mass: 63.98264
  			},
  			{
  				nominal: 65,
  				mass: 64.9875
  			},
  			{
  				nominal: 66,
  				mass: 65.99398
  			}
  		],
  		symbol: "V",
  		mass: 50.941465037425004,
  		name: "Vanadium",
  		monoisotopicMass: 50.94395704
  	},
  	{
  		number: 24,
  		isotopes: [
  			{
  				nominal: 42,
  				mass: 42.0067
  			},
  			{
  				nominal: 43,
  				mass: 42.99753
  			},
  			{
  				nominal: 44,
  				mass: 43.98536
  			},
  			{
  				nominal: 45,
  				mass: 44.97905
  			},
  			{
  				nominal: 46,
  				mass: 45.968359
  			},
  			{
  				nominal: 47,
  				mass: 46.9628974
  			},
  			{
  				nominal: 48,
  				mass: 47.9540291
  			},
  			{
  				nominal: 49,
  				mass: 48.9513333
  			},
  			{
  				nominal: 50,
  				mass: 49.94604183,
  				abundance: 0.04345
  			},
  			{
  				nominal: 51,
  				mass: 50.94476502
  			},
  			{
  				nominal: 52,
  				mass: 51.94050623,
  				abundance: 0.83789
  			},
  			{
  				nominal: 53,
  				mass: 52.94064815,
  				abundance: 0.09501
  			},
  			{
  				nominal: 54,
  				mass: 53.93887916,
  				abundance: 0.02365
  			},
  			{
  				nominal: 55,
  				mass: 54.94083843
  			},
  			{
  				nominal: 56,
  				mass: 55.9406531
  			},
  			{
  				nominal: 57,
  				mass: 56.943613
  			},
  			{
  				nominal: 58,
  				mass: 57.94435
  			},
  			{
  				nominal: 59,
  				mass: 58.94859
  			},
  			{
  				nominal: 60,
  				mass: 59.95008
  			},
  			{
  				nominal: 61,
  				mass: 60.95442
  			},
  			{
  				nominal: 62,
  				mass: 61.9561
  			},
  			{
  				nominal: 63,
  				mass: 62.96165
  			},
  			{
  				nominal: 64,
  				mass: 63.96408
  			},
  			{
  				nominal: 65,
  				mass: 64.96996
  			},
  			{
  				nominal: 66,
  				mass: 65.97366
  			},
  			{
  				nominal: 67,
  				mass: 66.98016
  			},
  			{
  				nominal: 68,
  				mass: 67.98403
  			}
  		],
  		symbol: "Cr",
  		mass: 51.9961317554337,
  		name: "Chromium",
  		monoisotopicMass: 51.94050623
  	},
  	{
  		number: 25,
  		isotopes: [
  			{
  				nominal: 44,
  				mass: 44.00715
  			},
  			{
  				nominal: 45,
  				mass: 44.99449
  			},
  			{
  				nominal: 46,
  				mass: 45.98609
  			},
  			{
  				nominal: 47,
  				mass: 46.975775
  			},
  			{
  				nominal: 48,
  				mass: 47.96852
  			},
  			{
  				nominal: 49,
  				mass: 48.959595
  			},
  			{
  				nominal: 50,
  				mass: 49.95423778
  			},
  			{
  				nominal: 51,
  				mass: 50.94820847
  			},
  			{
  				nominal: 52,
  				mass: 51.9455639
  			},
  			{
  				nominal: 53,
  				mass: 52.94128889
  			},
  			{
  				nominal: 54,
  				mass: 53.9403576
  			},
  			{
  				nominal: 55,
  				mass: 54.93804391,
  				abundance: 1
  			},
  			{
  				nominal: 56,
  				mass: 55.93890369
  			},
  			{
  				nominal: 57,
  				mass: 56.9382861
  			},
  			{
  				nominal: 58,
  				mass: 57.9400666
  			},
  			{
  				nominal: 59,
  				mass: 58.9403911
  			},
  			{
  				nominal: 60,
  				mass: 59.9431366
  			},
  			{
  				nominal: 61,
  				mass: 60.9444525
  			},
  			{
  				nominal: 62,
  				mass: 61.94795
  			},
  			{
  				nominal: 63,
  				mass: 62.9496647
  			},
  			{
  				nominal: 64,
  				mass: 63.9538494
  			},
  			{
  				nominal: 65,
  				mass: 64.9560198
  			},
  			{
  				nominal: 66,
  				mass: 65.960547
  			},
  			{
  				nominal: 67,
  				mass: 66.96424
  			},
  			{
  				nominal: 68,
  				mass: 67.96962
  			},
  			{
  				nominal: 69,
  				mass: 68.97366
  			},
  			{
  				nominal: 70,
  				mass: 69.97937
  			},
  			{
  				nominal: 71,
  				mass: 70.98368
  			}
  		],
  		symbol: "Mn",
  		mass: 54.93804391,
  		name: "Manganese",
  		monoisotopicMass: 54.93804391
  	},
  	{
  		number: 26,
  		isotopes: [
  			{
  				nominal: 45,
  				mass: 45.01442
  			},
  			{
  				nominal: 46,
  				mass: 46.00063
  			},
  			{
  				nominal: 47,
  				mass: 46.99185
  			},
  			{
  				nominal: 48,
  				mass: 47.98023
  			},
  			{
  				nominal: 49,
  				mass: 48.973429
  			},
  			{
  				nominal: 50,
  				mass: 49.962975
  			},
  			{
  				nominal: 51,
  				mass: 50.956841
  			},
  			{
  				nominal: 52,
  				mass: 51.9481131
  			},
  			{
  				nominal: 53,
  				mass: 52.9453064
  			},
  			{
  				nominal: 54,
  				mass: 53.93960899,
  				abundance: 0.05845
  			},
  			{
  				nominal: 55,
  				mass: 54.93829199
  			},
  			{
  				nominal: 56,
  				mass: 55.93493633,
  				abundance: 0.91754
  			},
  			{
  				nominal: 57,
  				mass: 56.93539284,
  				abundance: 0.02119
  			},
  			{
  				nominal: 58,
  				mass: 57.93327443,
  				abundance: 0.00282
  			},
  			{
  				nominal: 59,
  				mass: 58.93487434
  			},
  			{
  				nominal: 60,
  				mass: 59.9340711
  			},
  			{
  				nominal: 61,
  				mass: 60.9367462
  			},
  			{
  				nominal: 62,
  				mass: 61.9367918
  			},
  			{
  				nominal: 63,
  				mass: 62.9402727
  			},
  			{
  				nominal: 64,
  				mass: 63.9409878
  			},
  			{
  				nominal: 65,
  				mass: 64.9450115
  			},
  			{
  				nominal: 66,
  				mass: 65.94625
  			},
  			{
  				nominal: 67,
  				mass: 66.95054
  			},
  			{
  				nominal: 68,
  				mass: 67.95295
  			},
  			{
  				nominal: 69,
  				mass: 68.95807
  			},
  			{
  				nominal: 70,
  				mass: 69.96102
  			},
  			{
  				nominal: 71,
  				mass: 70.96672
  			},
  			{
  				nominal: 72,
  				mass: 71.96983
  			},
  			{
  				nominal: 73,
  				mass: 72.97572
  			},
  			{
  				nominal: 74,
  				mass: 73.97935
  			}
  		],
  		symbol: "Fe",
  		mass: 55.845144433865904,
  		name: "Iron",
  		monoisotopicMass: 55.93493633
  	},
  	{
  		number: 27,
  		isotopes: [
  			{
  				nominal: 47,
  				mass: 47.01057
  			},
  			{
  				nominal: 48,
  				mass: 48.00093
  			},
  			{
  				nominal: 49,
  				mass: 48.98891
  			},
  			{
  				nominal: 50,
  				mass: 49.98091
  			},
  			{
  				nominal: 51,
  				mass: 50.970647
  			},
  			{
  				nominal: 52,
  				mass: 51.96351
  			},
  			{
  				nominal: 53,
  				mass: 52.9542041
  			},
  			{
  				nominal: 54,
  				mass: 53.94845987
  			},
  			{
  				nominal: 55,
  				mass: 54.9419972
  			},
  			{
  				nominal: 56,
  				mass: 55.9398388
  			},
  			{
  				nominal: 57,
  				mass: 56.93629057
  			},
  			{
  				nominal: 58,
  				mass: 57.9357521
  			},
  			{
  				nominal: 59,
  				mass: 58.93319429,
  				abundance: 1
  			},
  			{
  				nominal: 60,
  				mass: 59.9338163
  			},
  			{
  				nominal: 61,
  				mass: 60.93247662
  			},
  			{
  				nominal: 62,
  				mass: 61.934059
  			},
  			{
  				nominal: 63,
  				mass: 62.9336
  			},
  			{
  				nominal: 64,
  				mass: 63.935811
  			},
  			{
  				nominal: 65,
  				mass: 64.9364621
  			},
  			{
  				nominal: 66,
  				mass: 65.939443
  			},
  			{
  				nominal: 67,
  				mass: 66.9406096
  			},
  			{
  				nominal: 68,
  				mass: 67.94426
  			},
  			{
  				nominal: 69,
  				mass: 68.94614
  			},
  			{
  				nominal: 70,
  				mass: 69.94963
  			},
  			{
  				nominal: 71,
  				mass: 70.95237
  			},
  			{
  				nominal: 72,
  				mass: 71.95729
  			},
  			{
  				nominal: 73,
  				mass: 72.96039
  			},
  			{
  				nominal: 74,
  				mass: 73.96515
  			},
  			{
  				nominal: 75,
  				mass: 74.96876
  			},
  			{
  				nominal: 76,
  				mass: 75.97413
  			}
  		],
  		symbol: "Co",
  		mass: 58.93319429,
  		name: "Cobalt",
  		monoisotopicMass: 58.93319429
  	},
  	{
  		number: 28,
  		isotopes: [
  			{
  				nominal: 48,
  				mass: 48.01769
  			},
  			{
  				nominal: 49,
  				mass: 49.0077
  			},
  			{
  				nominal: 50,
  				mass: 49.99474
  			},
  			{
  				nominal: 51,
  				mass: 50.98611
  			},
  			{
  				nominal: 52,
  				mass: 51.9748
  			},
  			{
  				nominal: 53,
  				mass: 52.96819
  			},
  			{
  				nominal: 54,
  				mass: 53.957892
  			},
  			{
  				nominal: 55,
  				mass: 54.95133063
  			},
  			{
  				nominal: 56,
  				mass: 55.94212855
  			},
  			{
  				nominal: 57,
  				mass: 56.93979218
  			},
  			{
  				nominal: 58,
  				mass: 57.93534241,
  				abundance: 0.68077
  			},
  			{
  				nominal: 59,
  				mass: 58.9343462
  			},
  			{
  				nominal: 60,
  				mass: 59.93078588,
  				abundance: 0.26223
  			},
  			{
  				nominal: 61,
  				mass: 60.93105557,
  				abundance: 0.011399
  			},
  			{
  				nominal: 62,
  				mass: 61.92834537,
  				abundance: 0.036346
  			},
  			{
  				nominal: 63,
  				mass: 62.92966963
  			},
  			{
  				nominal: 64,
  				mass: 63.92796682,
  				abundance: 0.009255
  			},
  			{
  				nominal: 65,
  				mass: 64.93008517
  			},
  			{
  				nominal: 66,
  				mass: 65.9291393
  			},
  			{
  				nominal: 67,
  				mass: 66.9315694
  			},
  			{
  				nominal: 68,
  				mass: 67.9318688
  			},
  			{
  				nominal: 69,
  				mass: 68.9356103
  			},
  			{
  				nominal: 70,
  				mass: 69.9364313
  			},
  			{
  				nominal: 71,
  				mass: 70.940519
  			},
  			{
  				nominal: 72,
  				mass: 71.9417859
  			},
  			{
  				nominal: 73,
  				mass: 72.9462067
  			},
  			{
  				nominal: 74,
  				mass: 73.94798
  			},
  			{
  				nominal: 75,
  				mass: 74.9525
  			},
  			{
  				nominal: 76,
  				mass: 75.95533
  			},
  			{
  				nominal: 77,
  				mass: 76.96055
  			},
  			{
  				nominal: 78,
  				mass: 77.96336
  			},
  			{
  				nominal: 79,
  				mass: 78.97025
  			}
  		],
  		symbol: "Ni",
  		mass: 58.69334710994765,
  		name: "Nickel",
  		monoisotopicMass: 57.93534241
  	},
  	{
  		number: 29,
  		isotopes: [
  			{
  				nominal: 52,
  				mass: 51.99671
  			},
  			{
  				nominal: 53,
  				mass: 52.98459
  			},
  			{
  				nominal: 54,
  				mass: 53.97666
  			},
  			{
  				nominal: 55,
  				mass: 54.96604
  			},
  			{
  				nominal: 56,
  				mass: 55.95895
  			},
  			{
  				nominal: 57,
  				mass: 56.9492125
  			},
  			{
  				nominal: 58,
  				mass: 57.94453305
  			},
  			{
  				nominal: 59,
  				mass: 58.93949748
  			},
  			{
  				nominal: 60,
  				mass: 59.9373645
  			},
  			{
  				nominal: 61,
  				mass: 60.9334576
  			},
  			{
  				nominal: 62,
  				mass: 61.93259541
  			},
  			{
  				nominal: 63,
  				mass: 62.92959772,
  				abundance: 0.6915
  			},
  			{
  				nominal: 64,
  				mass: 63.92976434
  			},
  			{
  				nominal: 65,
  				mass: 64.9277897,
  				abundance: 0.3085
  			},
  			{
  				nominal: 66,
  				mass: 65.92886903
  			},
  			{
  				nominal: 67,
  				mass: 66.9277303
  			},
  			{
  				nominal: 68,
  				mass: 67.9296109
  			},
  			{
  				nominal: 69,
  				mass: 68.9294293
  			},
  			{
  				nominal: 70,
  				mass: 69.9323921
  			},
  			{
  				nominal: 71,
  				mass: 70.9326768
  			},
  			{
  				nominal: 72,
  				mass: 71.9358203
  			},
  			{
  				nominal: 73,
  				mass: 72.9366744
  			},
  			{
  				nominal: 74,
  				mass: 73.9398749
  			},
  			{
  				nominal: 75,
  				mass: 74.9415226
  			},
  			{
  				nominal: 76,
  				mass: 75.945275
  			},
  			{
  				nominal: 77,
  				mass: 76.94792
  			},
  			{
  				nominal: 78,
  				mass: 77.95223
  			},
  			{
  				nominal: 79,
  				mass: 78.95502
  			},
  			{
  				nominal: 80,
  				mass: 79.96089
  			},
  			{
  				nominal: 81,
  				mass: 80.96587
  			},
  			{
  				nominal: 82,
  				mass: 81.97244
  			}
  		],
  		symbol: "Cu",
  		mass: 63.54603994583,
  		name: "Copper",
  		monoisotopicMass: 62.92959772
  	},
  	{
  		number: 30,
  		isotopes: [
  			{
  				nominal: 54,
  				mass: 53.99204
  			},
  			{
  				nominal: 55,
  				mass: 54.98398
  			},
  			{
  				nominal: 56,
  				mass: 55.97254
  			},
  			{
  				nominal: 57,
  				mass: 56.96506
  			},
  			{
  				nominal: 58,
  				mass: 57.954591
  			},
  			{
  				nominal: 59,
  				mass: 58.94931266
  			},
  			{
  				nominal: 60,
  				mass: 59.9418421
  			},
  			{
  				nominal: 61,
  				mass: 60.939507
  			},
  			{
  				nominal: 62,
  				mass: 61.93433397
  			},
  			{
  				nominal: 63,
  				mass: 62.9332115
  			},
  			{
  				nominal: 64,
  				mass: 63.92914201,
  				abundance: 0.4917
  			},
  			{
  				nominal: 65,
  				mass: 64.92924077
  			},
  			{
  				nominal: 66,
  				mass: 65.92603381,
  				abundance: 0.2773
  			},
  			{
  				nominal: 67,
  				mass: 66.92712775,
  				abundance: 0.0404
  			},
  			{
  				nominal: 68,
  				mass: 67.92484455,
  				abundance: 0.1845
  			},
  			{
  				nominal: 69,
  				mass: 68.9265507
  			},
  			{
  				nominal: 70,
  				mass: 69.9253192,
  				abundance: 0.0061
  			},
  			{
  				nominal: 71,
  				mass: 70.9277196
  			},
  			{
  				nominal: 72,
  				mass: 71.9268428
  			},
  			{
  				nominal: 73,
  				mass: 72.9295826
  			},
  			{
  				nominal: 74,
  				mass: 73.9294073
  			},
  			{
  				nominal: 75,
  				mass: 74.9328402
  			},
  			{
  				nominal: 76,
  				mass: 75.933115
  			},
  			{
  				nominal: 77,
  				mass: 76.9368872
  			},
  			{
  				nominal: 78,
  				mass: 77.9382892
  			},
  			{
  				nominal: 79,
  				mass: 78.9426381
  			},
  			{
  				nominal: 80,
  				mass: 79.9445529
  			},
  			{
  				nominal: 81,
  				mass: 80.9504026
  			},
  			{
  				nominal: 82,
  				mass: 81.95426
  			},
  			{
  				nominal: 83,
  				mass: 82.96056
  			},
  			{
  				nominal: 84,
  				mass: 83.96521
  			},
  			{
  				nominal: 85,
  				mass: 84.97226
  			}
  		],
  		symbol: "Zn",
  		mass: 65.37778252952499,
  		name: "Zinc",
  		monoisotopicMass: 63.92914201
  	},
  	{
  		number: 31,
  		isotopes: [
  			{
  				nominal: 56,
  				mass: 55.99536
  			},
  			{
  				nominal: 57,
  				mass: 56.9832
  			},
  			{
  				nominal: 58,
  				mass: 57.97478
  			},
  			{
  				nominal: 59,
  				mass: 58.96353
  			},
  			{
  				nominal: 60,
  				mass: 59.95729
  			},
  			{
  				nominal: 61,
  				mass: 60.949399
  			},
  			{
  				nominal: 62,
  				mass: 61.94419025
  			},
  			{
  				nominal: 63,
  				mass: 62.9392942
  			},
  			{
  				nominal: 64,
  				mass: 63.9368404
  			},
  			{
  				nominal: 65,
  				mass: 64.93273459
  			},
  			{
  				nominal: 66,
  				mass: 65.9315894
  			},
  			{
  				nominal: 67,
  				mass: 66.9282025
  			},
  			{
  				nominal: 68,
  				mass: 67.9279805
  			},
  			{
  				nominal: 69,
  				mass: 68.9255735,
  				abundance: 0.60108
  			},
  			{
  				nominal: 70,
  				mass: 69.9260219
  			},
  			{
  				nominal: 71,
  				mass: 70.92470258,
  				abundance: 0.39892
  			},
  			{
  				nominal: 72,
  				mass: 71.92636747
  			},
  			{
  				nominal: 73,
  				mass: 72.9251747
  			},
  			{
  				nominal: 74,
  				mass: 73.9269457
  			},
  			{
  				nominal: 75,
  				mass: 74.9265002
  			},
  			{
  				nominal: 76,
  				mass: 75.9288276
  			},
  			{
  				nominal: 77,
  				mass: 76.9291543
  			},
  			{
  				nominal: 78,
  				mass: 77.9316088
  			},
  			{
  				nominal: 79,
  				mass: 78.9328523
  			},
  			{
  				nominal: 80,
  				mass: 79.9364208
  			},
  			{
  				nominal: 81,
  				mass: 80.9381338
  			},
  			{
  				nominal: 82,
  				mass: 81.9431765
  			},
  			{
  				nominal: 83,
  				mass: 82.9471203
  			},
  			{
  				nominal: 84,
  				mass: 83.95246
  			},
  			{
  				nominal: 85,
  				mass: 84.95699
  			},
  			{
  				nominal: 86,
  				mass: 85.96301
  			},
  			{
  				nominal: 87,
  				mass: 86.96824
  			}
  		],
  		symbol: "Ga",
  		mass: 69.7230660725936,
  		name: "Gallium",
  		monoisotopicMass: 68.9255735
  	},
  	{
  		number: 32,
  		isotopes: [
  			{
  				nominal: 58,
  				mass: 57.99172
  			},
  			{
  				nominal: 59,
  				mass: 58.98249
  			},
  			{
  				nominal: 60,
  				mass: 59.97036
  			},
  			{
  				nominal: 61,
  				mass: 60.96379
  			},
  			{
  				nominal: 62,
  				mass: 61.95502
  			},
  			{
  				nominal: 63,
  				mass: 62.949628
  			},
  			{
  				nominal: 64,
  				mass: 63.9416899
  			},
  			{
  				nominal: 65,
  				mass: 64.9393681
  			},
  			{
  				nominal: 66,
  				mass: 65.9338621
  			},
  			{
  				nominal: 67,
  				mass: 66.9327339
  			},
  			{
  				nominal: 68,
  				mass: 67.9280953
  			},
  			{
  				nominal: 69,
  				mass: 68.9279645
  			},
  			{
  				nominal: 70,
  				mass: 69.92424875,
  				abundance: 0.2057
  			},
  			{
  				nominal: 71,
  				mass: 70.92495233
  			},
  			{
  				nominal: 72,
  				mass: 71.922075826,
  				abundance: 0.2745
  			},
  			{
  				nominal: 73,
  				mass: 72.923458956,
  				abundance: 0.0775
  			},
  			{
  				nominal: 74,
  				mass: 73.921177761,
  				abundance: 0.365
  			},
  			{
  				nominal: 75,
  				mass: 74.92285837
  			},
  			{
  				nominal: 76,
  				mass: 75.921402726,
  				abundance: 0.0773
  			},
  			{
  				nominal: 77,
  				mass: 76.923549843
  			},
  			{
  				nominal: 78,
  				mass: 77.9228529
  			},
  			{
  				nominal: 79,
  				mass: 78.92536
  			},
  			{
  				nominal: 80,
  				mass: 79.9253508
  			},
  			{
  				nominal: 81,
  				mass: 80.9288329
  			},
  			{
  				nominal: 82,
  				mass: 81.929774
  			},
  			{
  				nominal: 83,
  				mass: 82.9345391
  			},
  			{
  				nominal: 84,
  				mass: 83.9375751
  			},
  			{
  				nominal: 85,
  				mass: 84.9429697
  			},
  			{
  				nominal: 86,
  				mass: 85.94658
  			},
  			{
  				nominal: 87,
  				mass: 86.95268
  			},
  			{
  				nominal: 88,
  				mass: 87.95691
  			},
  			{
  				nominal: 89,
  				mass: 88.96379
  			},
  			{
  				nominal: 90,
  				mass: 89.96863
  			}
  		],
  		symbol: "Ge",
  		mass: 72.6275501646868,
  		name: "Germanium",
  		monoisotopicMass: 73.921177761
  	},
  	{
  		number: 33,
  		isotopes: [
  			{
  				nominal: 60,
  				mass: 59.99388
  			},
  			{
  				nominal: 61,
  				mass: 60.98112
  			},
  			{
  				nominal: 62,
  				mass: 61.97361
  			},
  			{
  				nominal: 63,
  				mass: 62.9639
  			},
  			{
  				nominal: 64,
  				mass: 63.95743
  			},
  			{
  				nominal: 65,
  				mass: 64.949611
  			},
  			{
  				nominal: 66,
  				mass: 65.9441488
  			},
  			{
  				nominal: 67,
  				mass: 66.93925111
  			},
  			{
  				nominal: 68,
  				mass: 67.9367741
  			},
  			{
  				nominal: 69,
  				mass: 68.932246
  			},
  			{
  				nominal: 70,
  				mass: 69.930926
  			},
  			{
  				nominal: 71,
  				mass: 70.9271138
  			},
  			{
  				nominal: 72,
  				mass: 71.9267523
  			},
  			{
  				nominal: 73,
  				mass: 72.9238291
  			},
  			{
  				nominal: 74,
  				mass: 73.9239286
  			},
  			{
  				nominal: 75,
  				mass: 74.92159457,
  				abundance: 1
  			},
  			{
  				nominal: 76,
  				mass: 75.92239202
  			},
  			{
  				nominal: 77,
  				mass: 76.9206476
  			},
  			{
  				nominal: 78,
  				mass: 77.921828
  			},
  			{
  				nominal: 79,
  				mass: 78.9209484
  			},
  			{
  				nominal: 80,
  				mass: 79.9224746
  			},
  			{
  				nominal: 81,
  				mass: 80.9221323
  			},
  			{
  				nominal: 82,
  				mass: 81.9247412
  			},
  			{
  				nominal: 83,
  				mass: 82.9252069
  			},
  			{
  				nominal: 84,
  				mass: 83.9293033
  			},
  			{
  				nominal: 85,
  				mass: 84.9321637
  			},
  			{
  				nominal: 86,
  				mass: 85.9367015
  			},
  			{
  				nominal: 87,
  				mass: 86.9402917
  			},
  			{
  				nominal: 88,
  				mass: 87.94555
  			},
  			{
  				nominal: 89,
  				mass: 88.94976
  			},
  			{
  				nominal: 90,
  				mass: 89.95563
  			},
  			{
  				nominal: 91,
  				mass: 90.96039
  			},
  			{
  				nominal: 92,
  				mass: 91.96674
  			}
  		],
  		symbol: "As",
  		mass: 74.92159457,
  		name: "Arsenic",
  		monoisotopicMass: 74.92159457
  	},
  	{
  		number: 34,
  		isotopes: [
  			{
  				nominal: 64,
  				mass: 63.97109
  			},
  			{
  				nominal: 65,
  				mass: 64.9644
  			},
  			{
  				nominal: 66,
  				mass: 65.95559
  			},
  			{
  				nominal: 67,
  				mass: 66.949994
  			},
  			{
  				nominal: 68,
  				mass: 67.94182524
  			},
  			{
  				nominal: 69,
  				mass: 68.9394148
  			},
  			{
  				nominal: 70,
  				mass: 69.9335155
  			},
  			{
  				nominal: 71,
  				mass: 70.9322094
  			},
  			{
  				nominal: 72,
  				mass: 71.9271405
  			},
  			{
  				nominal: 73,
  				mass: 72.9267549
  			},
  			{
  				nominal: 74,
  				mass: 73.922475934,
  				abundance: 0.0089
  			},
  			{
  				nominal: 75,
  				mass: 74.92252287
  			},
  			{
  				nominal: 76,
  				mass: 75.919213704,
  				abundance: 0.0937
  			},
  			{
  				nominal: 77,
  				mass: 76.919914154,
  				abundance: 0.0763
  			},
  			{
  				nominal: 78,
  				mass: 77.91730928,
  				abundance: 0.2377
  			},
  			{
  				nominal: 79,
  				mass: 78.91849929
  			},
  			{
  				nominal: 80,
  				mass: 79.9165218,
  				abundance: 0.4961
  			},
  			{
  				nominal: 81,
  				mass: 80.917993
  			},
  			{
  				nominal: 82,
  				mass: 81.9166995,
  				abundance: 0.0873
  			},
  			{
  				nominal: 83,
  				mass: 82.9191186
  			},
  			{
  				nominal: 84,
  				mass: 83.9184668
  			},
  			{
  				nominal: 85,
  				mass: 84.9222608
  			},
  			{
  				nominal: 86,
  				mass: 85.9243117
  			},
  			{
  				nominal: 87,
  				mass: 86.9286886
  			},
  			{
  				nominal: 88,
  				mass: 87.9314175
  			},
  			{
  				nominal: 89,
  				mass: 88.9366691
  			},
  			{
  				nominal: 90,
  				mass: 89.9401
  			},
  			{
  				nominal: 91,
  				mass: 90.94596
  			},
  			{
  				nominal: 92,
  				mass: 91.94984
  			},
  			{
  				nominal: 93,
  				mass: 92.95629
  			},
  			{
  				nominal: 94,
  				mass: 93.96049
  			},
  			{
  				nominal: 95,
  				mass: 94.9673
  			}
  		],
  		symbol: "Se",
  		mass: 78.95938855701361,
  		name: "Selenium",
  		monoisotopicMass: 79.9165218
  	},
  	{
  		number: 35,
  		isotopes: [
  			{
  				nominal: 67,
  				mass: 66.96465
  			},
  			{
  				nominal: 68,
  				mass: 67.95873
  			},
  			{
  				nominal: 69,
  				mass: 68.950497
  			},
  			{
  				nominal: 70,
  				mass: 69.944792
  			},
  			{
  				nominal: 71,
  				mass: 70.9393422
  			},
  			{
  				nominal: 72,
  				mass: 71.9365886
  			},
  			{
  				nominal: 73,
  				mass: 72.9316715
  			},
  			{
  				nominal: 74,
  				mass: 73.9299102
  			},
  			{
  				nominal: 75,
  				mass: 74.9258105
  			},
  			{
  				nominal: 76,
  				mass: 75.924542
  			},
  			{
  				nominal: 77,
  				mass: 76.9213792
  			},
  			{
  				nominal: 78,
  				mass: 77.9211459
  			},
  			{
  				nominal: 79,
  				mass: 78.9183376,
  				abundance: 0.5069
  			},
  			{
  				nominal: 80,
  				mass: 79.9185298
  			},
  			{
  				nominal: 81,
  				mass: 80.9162897,
  				abundance: 0.4931
  			},
  			{
  				nominal: 82,
  				mass: 81.9168032
  			},
  			{
  				nominal: 83,
  				mass: 82.9151756
  			},
  			{
  				nominal: 84,
  				mass: 83.916496
  			},
  			{
  				nominal: 85,
  				mass: 84.9156458
  			},
  			{
  				nominal: 86,
  				mass: 85.9188054
  			},
  			{
  				nominal: 87,
  				mass: 86.920674
  			},
  			{
  				nominal: 88,
  				mass: 87.9240833
  			},
  			{
  				nominal: 89,
  				mass: 88.9267046
  			},
  			{
  				nominal: 90,
  				mass: 89.9312928
  			},
  			{
  				nominal: 91,
  				mass: 90.9343986
  			},
  			{
  				nominal: 92,
  				mass: 91.9396316
  			},
  			{
  				nominal: 93,
  				mass: 92.94313
  			},
  			{
  				nominal: 94,
  				mass: 93.9489
  			},
  			{
  				nominal: 95,
  				mass: 94.95301
  			},
  			{
  				nominal: 96,
  				mass: 95.95903
  			},
  			{
  				nominal: 97,
  				mass: 96.96344
  			},
  			{
  				nominal: 98,
  				mass: 97.96946
  			}
  		],
  		symbol: "Br",
  		mass: 79.90352778050999,
  		name: "Bromine",
  		monoisotopicMass: 78.9183376
  	},
  	{
  		number: 36,
  		isotopes: [
  			{
  				nominal: 69,
  				mass: 68.96518
  			},
  			{
  				nominal: 70,
  				mass: 69.95604
  			},
  			{
  				nominal: 71,
  				mass: 70.95027
  			},
  			{
  				nominal: 72,
  				mass: 71.9420924
  			},
  			{
  				nominal: 73,
  				mass: 72.9392892
  			},
  			{
  				nominal: 74,
  				mass: 73.933084
  			},
  			{
  				nominal: 75,
  				mass: 74.9309457
  			},
  			{
  				nominal: 76,
  				mass: 75.9259103
  			},
  			{
  				nominal: 77,
  				mass: 76.92467
  			},
  			{
  				nominal: 78,
  				mass: 77.92036494,
  				abundance: 0.00355
  			},
  			{
  				nominal: 79,
  				mass: 78.9200829
  			},
  			{
  				nominal: 80,
  				mass: 79.91637808,
  				abundance: 0.02286
  			},
  			{
  				nominal: 81,
  				mass: 80.9165912
  			},
  			{
  				nominal: 82,
  				mass: 81.91348273,
  				abundance: 0.11593
  			},
  			{
  				nominal: 83,
  				mass: 82.91412716,
  				abundance: 0.115
  			},
  			{
  				nominal: 84,
  				mass: 83.9114977282,
  				abundance: 0.56987
  			},
  			{
  				nominal: 85,
  				mass: 84.9125273
  			},
  			{
  				nominal: 86,
  				mass: 85.9106106269,
  				abundance: 0.17279
  			},
  			{
  				nominal: 87,
  				mass: 86.91335476
  			},
  			{
  				nominal: 88,
  				mass: 87.9144479
  			},
  			{
  				nominal: 89,
  				mass: 88.9178355
  			},
  			{
  				nominal: 90,
  				mass: 89.9195279
  			},
  			{
  				nominal: 91,
  				mass: 90.9238063
  			},
  			{
  				nominal: 92,
  				mass: 91.9261731
  			},
  			{
  				nominal: 93,
  				mass: 92.9311472
  			},
  			{
  				nominal: 94,
  				mass: 93.93414
  			},
  			{
  				nominal: 95,
  				mass: 94.939711
  			},
  			{
  				nominal: 96,
  				mass: 95.943017
  			},
  			{
  				nominal: 97,
  				mass: 96.94909
  			},
  			{
  				nominal: 98,
  				mass: 97.95243
  			},
  			{
  				nominal: 99,
  				mass: 98.95839
  			},
  			{
  				nominal: 100,
  				mass: 99.96237
  			},
  			{
  				nominal: 101,
  				mass: 100.96873
  			}
  		],
  		symbol: "Kr",
  		mass: 83.7979999953261,
  		name: "Krypton",
  		monoisotopicMass: 83.9114977282
  	},
  	{
  		number: 37,
  		isotopes: [
  			{
  				nominal: 71,
  				mass: 70.96532
  			},
  			{
  				nominal: 72,
  				mass: 71.95908
  			},
  			{
  				nominal: 73,
  				mass: 72.95053
  			},
  			{
  				nominal: 74,
  				mass: 73.9442659
  			},
  			{
  				nominal: 75,
  				mass: 74.9385732
  			},
  			{
  				nominal: 76,
  				mass: 75.935073
  			},
  			{
  				nominal: 77,
  				mass: 76.9304016
  			},
  			{
  				nominal: 78,
  				mass: 77.9281419
  			},
  			{
  				nominal: 79,
  				mass: 78.9239899
  			},
  			{
  				nominal: 80,
  				mass: 79.9225164
  			},
  			{
  				nominal: 81,
  				mass: 80.9189939
  			},
  			{
  				nominal: 82,
  				mass: 81.918209
  			},
  			{
  				nominal: 83,
  				mass: 82.9151142
  			},
  			{
  				nominal: 84,
  				mass: 83.9143752
  			},
  			{
  				nominal: 85,
  				mass: 84.9117897379,
  				abundance: 0.7217
  			},
  			{
  				nominal: 86,
  				mass: 85.91116743
  			},
  			{
  				nominal: 87,
  				mass: 86.909180531,
  				abundance: 0.2783
  			},
  			{
  				nominal: 88,
  				mass: 87.91131559
  			},
  			{
  				nominal: 89,
  				mass: 88.9122783
  			},
  			{
  				nominal: 90,
  				mass: 89.9147985
  			},
  			{
  				nominal: 91,
  				mass: 90.9165372
  			},
  			{
  				nominal: 92,
  				mass: 91.9197284
  			},
  			{
  				nominal: 93,
  				mass: 92.9220393
  			},
  			{
  				nominal: 94,
  				mass: 93.9263948
  			},
  			{
  				nominal: 95,
  				mass: 94.92926
  			},
  			{
  				nominal: 96,
  				mass: 95.9341334
  			},
  			{
  				nominal: 97,
  				mass: 96.9371771
  			},
  			{
  				nominal: 98,
  				mass: 97.9416869
  			},
  			{
  				nominal: 99,
  				mass: 98.94503
  			},
  			{
  				nominal: 100,
  				mass: 99.95003
  			},
  			{
  				nominal: 101,
  				mass: 100.95404
  			},
  			{
  				nominal: 102,
  				mass: 101.95952
  			},
  			{
  				nominal: 103,
  				mass: 102.96392
  			}
  		],
  		symbol: "Rb",
  		mass: 85.46766359561973,
  		name: "Rubidium",
  		monoisotopicMass: 84.9117897379
  	},
  	{
  		number: 38,
  		isotopes: [
  			{
  				nominal: 73,
  				mass: 72.9657
  			},
  			{
  				nominal: 74,
  				mass: 73.95617
  			},
  			{
  				nominal: 75,
  				mass: 74.94995
  			},
  			{
  				nominal: 76,
  				mass: 75.941763
  			},
  			{
  				nominal: 77,
  				mass: 76.9379455
  			},
  			{
  				nominal: 78,
  				mass: 77.93218
  			},
  			{
  				nominal: 79,
  				mass: 78.9297077
  			},
  			{
  				nominal: 80,
  				mass: 79.9245175
  			},
  			{
  				nominal: 81,
  				mass: 80.9232114
  			},
  			{
  				nominal: 82,
  				mass: 81.9183999
  			},
  			{
  				nominal: 83,
  				mass: 82.9175544
  			},
  			{
  				nominal: 84,
  				mass: 83.9134191,
  				abundance: 0.0056
  			},
  			{
  				nominal: 85,
  				mass: 84.912932
  			},
  			{
  				nominal: 86,
  				mass: 85.9092606,
  				abundance: 0.0986
  			},
  			{
  				nominal: 87,
  				mass: 86.9088775,
  				abundance: 0.07
  			},
  			{
  				nominal: 88,
  				mass: 87.9056125,
  				abundance: 0.8258
  			},
  			{
  				nominal: 89,
  				mass: 88.9074511
  			},
  			{
  				nominal: 90,
  				mass: 89.90773
  			},
  			{
  				nominal: 91,
  				mass: 90.9101954
  			},
  			{
  				nominal: 92,
  				mass: 91.9110382
  			},
  			{
  				nominal: 93,
  				mass: 92.9140242
  			},
  			{
  				nominal: 94,
  				mass: 93.9153556
  			},
  			{
  				nominal: 95,
  				mass: 94.9193529
  			},
  			{
  				nominal: 96,
  				mass: 95.9217066
  			},
  			{
  				nominal: 97,
  				mass: 96.926374
  			},
  			{
  				nominal: 98,
  				mass: 97.9286888
  			},
  			{
  				nominal: 99,
  				mass: 98.9328907
  			},
  			{
  				nominal: 100,
  				mass: 99.93577
  			},
  			{
  				nominal: 101,
  				mass: 100.940352
  			},
  			{
  				nominal: 102,
  				mass: 101.943791
  			},
  			{
  				nominal: 103,
  				mass: 102.94909
  			},
  			{
  				nominal: 104,
  				mass: 103.95265
  			},
  			{
  				nominal: 105,
  				mass: 104.95855
  			},
  			{
  				nominal: 106,
  				mass: 105.96265
  			},
  			{
  				nominal: 107,
  				mass: 106.96897
  			}
  		],
  		symbol: "Sr",
  		mass: 87.61664446962,
  		name: "Strontium",
  		monoisotopicMass: 87.9056125
  	},
  	{
  		number: 39,
  		isotopes: [
  			{
  				nominal: 76,
  				mass: 75.95856
  			},
  			{
  				nominal: 77,
  				mass: 76.949781
  			},
  			{
  				nominal: 78,
  				mass: 77.94361
  			},
  			{
  				nominal: 79,
  				mass: 78.93735
  			},
  			{
  				nominal: 80,
  				mass: 79.9343561
  			},
  			{
  				nominal: 81,
  				mass: 80.9294556
  			},
  			{
  				nominal: 82,
  				mass: 81.9269314
  			},
  			{
  				nominal: 83,
  				mass: 82.922485
  			},
  			{
  				nominal: 84,
  				mass: 83.9206721
  			},
  			{
  				nominal: 85,
  				mass: 84.916433
  			},
  			{
  				nominal: 86,
  				mass: 85.914886
  			},
  			{
  				nominal: 87,
  				mass: 86.9108761
  			},
  			{
  				nominal: 88,
  				mass: 87.9095016
  			},
  			{
  				nominal: 89,
  				mass: 88.9058403,
  				abundance: 1
  			},
  			{
  				nominal: 90,
  				mass: 89.9071439
  			},
  			{
  				nominal: 91,
  				mass: 90.9072974
  			},
  			{
  				nominal: 92,
  				mass: 91.9089451
  			},
  			{
  				nominal: 93,
  				mass: 92.909578
  			},
  			{
  				nominal: 94,
  				mass: 93.9115906
  			},
  			{
  				nominal: 95,
  				mass: 94.9128161
  			},
  			{
  				nominal: 96,
  				mass: 95.9158968
  			},
  			{
  				nominal: 97,
  				mass: 96.9182741
  			},
  			{
  				nominal: 98,
  				mass: 97.9223821
  			},
  			{
  				nominal: 99,
  				mass: 98.924148
  			},
  			{
  				nominal: 100,
  				mass: 99.927715
  			},
  			{
  				nominal: 101,
  				mass: 100.9301477
  			},
  			{
  				nominal: 102,
  				mass: 101.9343277
  			},
  			{
  				nominal: 103,
  				mass: 102.937243
  			},
  			{
  				nominal: 104,
  				mass: 103.94196
  			},
  			{
  				nominal: 105,
  				mass: 104.94544
  			},
  			{
  				nominal: 106,
  				mass: 105.95056
  			},
  			{
  				nominal: 107,
  				mass: 106.95452
  			},
  			{
  				nominal: 108,
  				mass: 107.95996
  			},
  			{
  				nominal: 109,
  				mass: 108.96436
  			}
  		],
  		symbol: "Y",
  		mass: 88.9058403,
  		name: "Yttrium",
  		monoisotopicMass: 88.9058403
  	},
  	{
  		number: 40,
  		isotopes: [
  			{
  				nominal: 78,
  				mass: 77.95566
  			},
  			{
  				nominal: 79,
  				mass: 78.94948
  			},
  			{
  				nominal: 80,
  				mass: 79.9404
  			},
  			{
  				nominal: 81,
  				mass: 80.93731
  			},
  			{
  				nominal: 82,
  				mass: 81.93135
  			},
  			{
  				nominal: 83,
  				mass: 82.9292421
  			},
  			{
  				nominal: 84,
  				mass: 83.9233269
  			},
  			{
  				nominal: 85,
  				mass: 84.9214444
  			},
  			{
  				nominal: 86,
  				mass: 85.9162972
  			},
  			{
  				nominal: 87,
  				mass: 86.914818
  			},
  			{
  				nominal: 88,
  				mass: 87.9102213
  			},
  			{
  				nominal: 89,
  				mass: 88.9088814
  			},
  			{
  				nominal: 90,
  				mass: 89.9046977,
  				abundance: 0.5145
  			},
  			{
  				nominal: 91,
  				mass: 90.9056396,
  				abundance: 0.1122
  			},
  			{
  				nominal: 92,
  				mass: 91.9050347,
  				abundance: 0.1715
  			},
  			{
  				nominal: 93,
  				mass: 92.9064699
  			},
  			{
  				nominal: 94,
  				mass: 93.9063108,
  				abundance: 0.1738
  			},
  			{
  				nominal: 95,
  				mass: 94.9080385
  			},
  			{
  				nominal: 96,
  				mass: 95.9082714,
  				abundance: 0.028
  			},
  			{
  				nominal: 97,
  				mass: 96.9109512
  			},
  			{
  				nominal: 98,
  				mass: 97.9127289
  			},
  			{
  				nominal: 99,
  				mass: 98.916667
  			},
  			{
  				nominal: 100,
  				mass: 99.9180006
  			},
  			{
  				nominal: 101,
  				mass: 100.921448
  			},
  			{
  				nominal: 102,
  				mass: 101.9231409
  			},
  			{
  				nominal: 103,
  				mass: 102.927191
  			},
  			{
  				nominal: 104,
  				mass: 103.929436
  			},
  			{
  				nominal: 105,
  				mass: 104.934008
  			},
  			{
  				nominal: 106,
  				mass: 105.93676
  			},
  			{
  				nominal: 107,
  				mass: 106.94174
  			},
  			{
  				nominal: 108,
  				mass: 107.94487
  			},
  			{
  				nominal: 109,
  				mass: 108.95041
  			},
  			{
  				nominal: 110,
  				mass: 109.95396
  			},
  			{
  				nominal: 111,
  				mass: 110.95968
  			},
  			{
  				nominal: 112,
  				mass: 111.9637
  			}
  		],
  		symbol: "Zr",
  		mass: 91.22364159706,
  		name: "Zirconium",
  		monoisotopicMass: 89.9046977
  	},
  	{
  		number: 41,
  		isotopes: [
  			{
  				nominal: 81,
  				mass: 80.9496
  			},
  			{
  				nominal: 82,
  				mass: 81.94396
  			},
  			{
  				nominal: 83,
  				mass: 82.93729
  			},
  			{
  				nominal: 84,
  				mass: 83.93449
  			},
  			{
  				nominal: 85,
  				mass: 84.9288458
  			},
  			{
  				nominal: 86,
  				mass: 85.9257828
  			},
  			{
  				nominal: 87,
  				mass: 86.9206937
  			},
  			{
  				nominal: 88,
  				mass: 87.918222
  			},
  			{
  				nominal: 89,
  				mass: 88.913445
  			},
  			{
  				nominal: 90,
  				mass: 89.9112584
  			},
  			{
  				nominal: 91,
  				mass: 90.9069897
  			},
  			{
  				nominal: 92,
  				mass: 91.9071881
  			},
  			{
  				nominal: 93,
  				mass: 92.906373,
  				abundance: 1
  			},
  			{
  				nominal: 94,
  				mass: 93.9072788
  			},
  			{
  				nominal: 95,
  				mass: 94.9068324
  			},
  			{
  				nominal: 96,
  				mass: 95.9080973
  			},
  			{
  				nominal: 97,
  				mass: 96.9080959
  			},
  			{
  				nominal: 98,
  				mass: 97.9103265
  			},
  			{
  				nominal: 99,
  				mass: 98.911613
  			},
  			{
  				nominal: 100,
  				mass: 99.9143276
  			},
  			{
  				nominal: 101,
  				mass: 100.9153103
  			},
  			{
  				nominal: 102,
  				mass: 101.9180772
  			},
  			{
  				nominal: 103,
  				mass: 102.9194572
  			},
  			{
  				nominal: 104,
  				mass: 103.9228925
  			},
  			{
  				nominal: 105,
  				mass: 104.9249465
  			},
  			{
  				nominal: 106,
  				mass: 105.9289317
  			},
  			{
  				nominal: 107,
  				mass: 106.9315937
  			},
  			{
  				nominal: 108,
  				mass: 107.9360748
  			},
  			{
  				nominal: 109,
  				mass: 108.93922
  			},
  			{
  				nominal: 110,
  				mass: 109.94403
  			},
  			{
  				nominal: 111,
  				mass: 110.94753
  			},
  			{
  				nominal: 112,
  				mass: 111.95247
  			},
  			{
  				nominal: 113,
  				mass: 112.95651
  			},
  			{
  				nominal: 114,
  				mass: 113.96201
  			},
  			{
  				nominal: 115,
  				mass: 114.96634
  			}
  		],
  		symbol: "Nb",
  		mass: 92.906373,
  		name: "Niobium",
  		monoisotopicMass: 92.906373
  	},
  	{
  		number: 42,
  		isotopes: [
  			{
  				nominal: 83,
  				mass: 82.94988
  			},
  			{
  				nominal: 84,
  				mass: 83.94149
  			},
  			{
  				nominal: 85,
  				mass: 84.938261
  			},
  			{
  				nominal: 86,
  				mass: 85.9311748
  			},
  			{
  				nominal: 87,
  				mass: 86.9281962
  			},
  			{
  				nominal: 88,
  				mass: 87.9219678
  			},
  			{
  				nominal: 89,
  				mass: 88.9194682
  			},
  			{
  				nominal: 90,
  				mass: 89.9139309
  			},
  			{
  				nominal: 91,
  				mass: 90.9117453
  			},
  			{
  				nominal: 92,
  				mass: 91.90680796,
  				abundance: 0.1453
  			},
  			{
  				nominal: 93,
  				mass: 92.90680958
  			},
  			{
  				nominal: 94,
  				mass: 93.9050849,
  				abundance: 0.0915
  			},
  			{
  				nominal: 95,
  				mass: 94.90583877,
  				abundance: 0.1584
  			},
  			{
  				nominal: 96,
  				mass: 95.90467612,
  				abundance: 0.1667
  			},
  			{
  				nominal: 97,
  				mass: 96.90601812,
  				abundance: 0.096
  			},
  			{
  				nominal: 98,
  				mass: 97.90540482,
  				abundance: 0.2439
  			},
  			{
  				nominal: 99,
  				mass: 98.90770851
  			},
  			{
  				nominal: 100,
  				mass: 99.9074718,
  				abundance: 0.0982
  			},
  			{
  				nominal: 101,
  				mass: 100.9103414
  			},
  			{
  				nominal: 102,
  				mass: 101.9102834
  			},
  			{
  				nominal: 103,
  				mass: 102.913079
  			},
  			{
  				nominal: 104,
  				mass: 103.9137344
  			},
  			{
  				nominal: 105,
  				mass: 104.916969
  			},
  			{
  				nominal: 106,
  				mass: 105.918259
  			},
  			{
  				nominal: 107,
  				mass: 106.922106
  			},
  			{
  				nominal: 108,
  				mass: 107.924033
  			},
  			{
  				nominal: 109,
  				mass: 108.928424
  			},
  			{
  				nominal: 110,
  				mass: 109.930704
  			},
  			{
  				nominal: 111,
  				mass: 110.935654
  			},
  			{
  				nominal: 112,
  				mass: 111.93831
  			},
  			{
  				nominal: 113,
  				mass: 112.94335
  			},
  			{
  				nominal: 114,
  				mass: 113.94653
  			},
  			{
  				nominal: 115,
  				mass: 114.95196
  			},
  			{
  				nominal: 116,
  				mass: 115.95545
  			},
  			{
  				nominal: 117,
  				mass: 116.96117
  			}
  		],
  		symbol: "Mo",
  		mass: 95.959788541188,
  		name: "Molybdenum",
  		monoisotopicMass: 97.90540482
  	},
  	{
  		number: 43,
  		isotopes: [
  			{
  				nominal: 85,
  				mass: 84.95058
  			},
  			{
  				nominal: 86,
  				mass: 85.94493
  			},
  			{
  				nominal: 87,
  				mass: 86.9380672
  			},
  			{
  				nominal: 88,
  				mass: 87.93378
  			},
  			{
  				nominal: 89,
  				mass: 88.9276487
  			},
  			{
  				nominal: 90,
  				mass: 89.9240739
  			},
  			{
  				nominal: 91,
  				mass: 90.9184254
  			},
  			{
  				nominal: 92,
  				mass: 91.9152698
  			},
  			{
  				nominal: 93,
  				mass: 92.910246
  			},
  			{
  				nominal: 94,
  				mass: 93.9096536
  			},
  			{
  				nominal: 95,
  				mass: 94.9076536
  			},
  			{
  				nominal: 96,
  				mass: 95.907868
  			},
  			{
  				nominal: 97,
  				mass: 96.9063667
  			},
  			{
  				nominal: 98,
  				mass: 97.9072124
  			},
  			{
  				nominal: 99,
  				mass: 98.9062508
  			},
  			{
  				nominal: 100,
  				mass: 99.9076539
  			},
  			{
  				nominal: 101,
  				mass: 100.907309
  			},
  			{
  				nominal: 102,
  				mass: 101.9092097
  			},
  			{
  				nominal: 103,
  				mass: 102.909176
  			},
  			{
  				nominal: 104,
  				mass: 103.911425
  			},
  			{
  				nominal: 105,
  				mass: 104.911655
  			},
  			{
  				nominal: 106,
  				mass: 105.914358
  			},
  			{
  				nominal: 107,
  				mass: 106.9154606
  			},
  			{
  				nominal: 108,
  				mass: 107.9184957
  			},
  			{
  				nominal: 109,
  				mass: 108.920256
  			},
  			{
  				nominal: 110,
  				mass: 109.923744
  			},
  			{
  				nominal: 111,
  				mass: 110.925901
  			},
  			{
  				nominal: 112,
  				mass: 111.9299458
  			},
  			{
  				nominal: 113,
  				mass: 112.932569
  			},
  			{
  				nominal: 114,
  				mass: 113.93691
  			},
  			{
  				nominal: 115,
  				mass: 114.93998
  			},
  			{
  				nominal: 116,
  				mass: 115.94476
  			},
  			{
  				nominal: 117,
  				mass: 116.94806
  			},
  			{
  				nominal: 118,
  				mass: 117.95299
  			},
  			{
  				nominal: 119,
  				mass: 118.95666
  			},
  			{
  				nominal: 120,
  				mass: 119.96187
  			}
  		],
  		symbol: "Tc",
  		mass: null,
  		name: "Technetium"
  	},
  	{
  		number: 44,
  		isotopes: [
  			{
  				nominal: 87,
  				mass: 86.95069
  			},
  			{
  				nominal: 88,
  				mass: 87.9416
  			},
  			{
  				nominal: 89,
  				mass: 88.93762
  			},
  			{
  				nominal: 90,
  				mass: 89.9303444
  			},
  			{
  				nominal: 91,
  				mass: 90.9267419
  			},
  			{
  				nominal: 92,
  				mass: 91.9202344
  			},
  			{
  				nominal: 93,
  				mass: 92.9171044
  			},
  			{
  				nominal: 94,
  				mass: 93.9113429
  			},
  			{
  				nominal: 95,
  				mass: 94.910406
  			},
  			{
  				nominal: 96,
  				mass: 95.90759025,
  				abundance: 0.0554
  			},
  			{
  				nominal: 97,
  				mass: 96.9075471
  			},
  			{
  				nominal: 98,
  				mass: 97.9052868,
  				abundance: 0.0187
  			},
  			{
  				nominal: 99,
  				mass: 98.9059341,
  				abundance: 0.1276
  			},
  			{
  				nominal: 100,
  				mass: 99.9042143,
  				abundance: 0.126
  			},
  			{
  				nominal: 101,
  				mass: 100.9055769,
  				abundance: 0.1706
  			},
  			{
  				nominal: 102,
  				mass: 101.9043441,
  				abundance: 0.3155
  			},
  			{
  				nominal: 103,
  				mass: 102.9063186
  			},
  			{
  				nominal: 104,
  				mass: 103.9054275,
  				abundance: 0.1862
  			},
  			{
  				nominal: 105,
  				mass: 104.9077476
  			},
  			{
  				nominal: 106,
  				mass: 105.9073291
  			},
  			{
  				nominal: 107,
  				mass: 106.909972
  			},
  			{
  				nominal: 108,
  				mass: 107.910188
  			},
  			{
  				nominal: 109,
  				mass: 108.913326
  			},
  			{
  				nominal: 110,
  				mass: 109.9140407
  			},
  			{
  				nominal: 111,
  				mass: 110.91757
  			},
  			{
  				nominal: 112,
  				mass: 111.918809
  			},
  			{
  				nominal: 113,
  				mass: 112.922844
  			},
  			{
  				nominal: 114,
  				mass: 113.9246136
  			},
  			{
  				nominal: 115,
  				mass: 114.92882
  			},
  			{
  				nominal: 116,
  				mass: 115.9312192
  			},
  			{
  				nominal: 117,
  				mass: 116.9361
  			},
  			{
  				nominal: 118,
  				mass: 117.93853
  			},
  			{
  				nominal: 119,
  				mass: 118.94357
  			},
  			{
  				nominal: 120,
  				mass: 119.94631
  			},
  			{
  				nominal: 121,
  				mass: 120.95164
  			},
  			{
  				nominal: 122,
  				mass: 121.95447
  			},
  			{
  				nominal: 123,
  				mass: 122.95989
  			},
  			{
  				nominal: 124,
  				mass: 123.96305
  			}
  		],
  		symbol: "Ru",
  		mass: 101.06494013916,
  		name: "Ruthenium",
  		monoisotopicMass: 101.9043441
  	},
  	{
  		number: 45,
  		isotopes: [
  			{
  				nominal: 89,
  				mass: 88.95058
  			},
  			{
  				nominal: 90,
  				mass: 89.94422
  			},
  			{
  				nominal: 91,
  				mass: 90.93688
  			},
  			{
  				nominal: 92,
  				mass: 91.9323677
  			},
  			{
  				nominal: 93,
  				mass: 92.9259128
  			},
  			{
  				nominal: 94,
  				mass: 93.9217305
  			},
  			{
  				nominal: 95,
  				mass: 94.9158979
  			},
  			{
  				nominal: 96,
  				mass: 95.914453
  			},
  			{
  				nominal: 97,
  				mass: 96.911329
  			},
  			{
  				nominal: 98,
  				mass: 97.910708
  			},
  			{
  				nominal: 99,
  				mass: 98.9081282
  			},
  			{
  				nominal: 100,
  				mass: 99.908117
  			},
  			{
  				nominal: 101,
  				mass: 100.9061606
  			},
  			{
  				nominal: 102,
  				mass: 101.9068374
  			},
  			{
  				nominal: 103,
  				mass: 102.905498,
  				abundance: 1
  			},
  			{
  				nominal: 104,
  				mass: 103.9066492
  			},
  			{
  				nominal: 105,
  				mass: 104.9056885
  			},
  			{
  				nominal: 106,
  				mass: 105.9072868
  			},
  			{
  				nominal: 107,
  				mass: 106.906748
  			},
  			{
  				nominal: 108,
  				mass: 107.908714
  			},
  			{
  				nominal: 109,
  				mass: 108.9087488
  			},
  			{
  				nominal: 110,
  				mass: 109.911079
  			},
  			{
  				nominal: 111,
  				mass: 110.9116423
  			},
  			{
  				nominal: 112,
  				mass: 111.914403
  			},
  			{
  				nominal: 113,
  				mass: 112.9154393
  			},
  			{
  				nominal: 114,
  				mass: 113.918718
  			},
  			{
  				nominal: 115,
  				mass: 114.9203116
  			},
  			{
  				nominal: 116,
  				mass: 115.924059
  			},
  			{
  				nominal: 117,
  				mass: 116.9260354
  			},
  			{
  				nominal: 118,
  				mass: 117.93034
  			},
  			{
  				nominal: 119,
  				mass: 118.932557
  			},
  			{
  				nominal: 120,
  				mass: 119.93686
  			},
  			{
  				nominal: 121,
  				mass: 120.93942
  			},
  			{
  				nominal: 122,
  				mass: 121.94399
  			},
  			{
  				nominal: 123,
  				mass: 122.94685
  			},
  			{
  				nominal: 124,
  				mass: 123.95151
  			},
  			{
  				nominal: 125,
  				mass: 124.95469
  			},
  			{
  				nominal: 126,
  				mass: 125.95946
  			}
  		],
  		symbol: "Rh",
  		mass: 102.905498,
  		name: "Rhodium",
  		monoisotopicMass: 102.905498
  	},
  	{
  		number: 46,
  		isotopes: [
  			{
  				nominal: 91,
  				mass: 90.95032
  			},
  			{
  				nominal: 92,
  				mass: 91.94088
  			},
  			{
  				nominal: 93,
  				mass: 92.93651
  			},
  			{
  				nominal: 94,
  				mass: 93.9290376
  			},
  			{
  				nominal: 95,
  				mass: 94.9248898
  			},
  			{
  				nominal: 96,
  				mass: 95.9182151
  			},
  			{
  				nominal: 97,
  				mass: 96.916472
  			},
  			{
  				nominal: 98,
  				mass: 97.9126983
  			},
  			{
  				nominal: 99,
  				mass: 98.9117748
  			},
  			{
  				nominal: 100,
  				mass: 99.908505
  			},
  			{
  				nominal: 101,
  				mass: 100.9082864
  			},
  			{
  				nominal: 102,
  				mass: 101.9056022,
  				abundance: 0.0102
  			},
  			{
  				nominal: 103,
  				mass: 102.9060809
  			},
  			{
  				nominal: 104,
  				mass: 103.9040305,
  				abundance: 0.1114
  			},
  			{
  				nominal: 105,
  				mass: 104.9050796,
  				abundance: 0.2233
  			},
  			{
  				nominal: 106,
  				mass: 105.9034804,
  				abundance: 0.2733
  			},
  			{
  				nominal: 107,
  				mass: 106.9051282
  			},
  			{
  				nominal: 108,
  				mass: 107.9038916,
  				abundance: 0.2646
  			},
  			{
  				nominal: 109,
  				mass: 108.9059504
  			},
  			{
  				nominal: 110,
  				mass: 109.9051722,
  				abundance: 0.1172
  			},
  			{
  				nominal: 111,
  				mass: 110.90768968
  			},
  			{
  				nominal: 112,
  				mass: 111.9073297
  			},
  			{
  				nominal: 113,
  				mass: 112.910261
  			},
  			{
  				nominal: 114,
  				mass: 113.9103686
  			},
  			{
  				nominal: 115,
  				mass: 114.913659
  			},
  			{
  				nominal: 116,
  				mass: 115.914297
  			},
  			{
  				nominal: 117,
  				mass: 116.9179547
  			},
  			{
  				nominal: 118,
  				mass: 117.9190667
  			},
  			{
  				nominal: 119,
  				mass: 118.9233402
  			},
  			{
  				nominal: 120,
  				mass: 119.9245511
  			},
  			{
  				nominal: 121,
  				mass: 120.9289503
  			},
  			{
  				nominal: 122,
  				mass: 121.930632
  			},
  			{
  				nominal: 123,
  				mass: 122.93514
  			},
  			{
  				nominal: 124,
  				mass: 123.93714
  			},
  			{
  				nominal: 125,
  				mass: 124.94179
  			},
  			{
  				nominal: 126,
  				mass: 125.94416
  			},
  			{
  				nominal: 127,
  				mass: 126.94907
  			},
  			{
  				nominal: 128,
  				mass: 127.95183
  			}
  		],
  		symbol: "Pd",
  		mass: 106.41532750734,
  		name: "Palladium",
  		monoisotopicMass: 105.9034804
  	},
  	{
  		number: 47,
  		isotopes: [
  			{
  				nominal: 93,
  				mass: 92.95033
  			},
  			{
  				nominal: 94,
  				mass: 93.94373
  			},
  			{
  				nominal: 95,
  				mass: 94.93602
  			},
  			{
  				nominal: 96,
  				mass: 95.930744
  			},
  			{
  				nominal: 97,
  				mass: 96.92397
  			},
  			{
  				nominal: 98,
  				mass: 97.92156
  			},
  			{
  				nominal: 99,
  				mass: 98.9176458
  			},
  			{
  				nominal: 100,
  				mass: 99.9161154
  			},
  			{
  				nominal: 101,
  				mass: 100.912684
  			},
  			{
  				nominal: 102,
  				mass: 101.9117047
  			},
  			{
  				nominal: 103,
  				mass: 102.9089631
  			},
  			{
  				nominal: 104,
  				mass: 103.9086239
  			},
  			{
  				nominal: 105,
  				mass: 104.9065256
  			},
  			{
  				nominal: 106,
  				mass: 105.9066636
  			},
  			{
  				nominal: 107,
  				mass: 106.9050916,
  				abundance: 0.51839
  			},
  			{
  				nominal: 108,
  				mass: 107.9059503
  			},
  			{
  				nominal: 109,
  				mass: 108.9047553,
  				abundance: 0.48161
  			},
  			{
  				nominal: 110,
  				mass: 109.9061102
  			},
  			{
  				nominal: 111,
  				mass: 110.9052959
  			},
  			{
  				nominal: 112,
  				mass: 111.9070486
  			},
  			{
  				nominal: 113,
  				mass: 112.906573
  			},
  			{
  				nominal: 114,
  				mass: 113.908823
  			},
  			{
  				nominal: 115,
  				mass: 114.908767
  			},
  			{
  				nominal: 116,
  				mass: 115.9113868
  			},
  			{
  				nominal: 117,
  				mass: 116.911774
  			},
  			{
  				nominal: 118,
  				mass: 117.9145955
  			},
  			{
  				nominal: 119,
  				mass: 118.91557
  			},
  			{
  				nominal: 120,
  				mass: 119.9187848
  			},
  			{
  				nominal: 121,
  				mass: 120.920125
  			},
  			{
  				nominal: 122,
  				mass: 121.923664
  			},
  			{
  				nominal: 123,
  				mass: 122.925337
  			},
  			{
  				nominal: 124,
  				mass: 123.92893
  			},
  			{
  				nominal: 125,
  				mass: 124.93105
  			},
  			{
  				nominal: 126,
  				mass: 125.93475
  			},
  			{
  				nominal: 127,
  				mass: 126.93711
  			},
  			{
  				nominal: 128,
  				mass: 127.94106
  			},
  			{
  				nominal: 129,
  				mass: 128.94395
  			},
  			{
  				nominal: 130,
  				mass: 129.9507
  			}
  		],
  		symbol: "Ag",
  		mass: 107.868149634557,
  		name: "Silver",
  		monoisotopicMass: 106.9050916
  	},
  	{
  		number: 48,
  		isotopes: [
  			{
  				nominal: 95,
  				mass: 94.94994
  			},
  			{
  				nominal: 96,
  				mass: 95.94034
  			},
  			{
  				nominal: 97,
  				mass: 96.9351
  			},
  			{
  				nominal: 98,
  				mass: 97.927389
  			},
  			{
  				nominal: 99,
  				mass: 98.9249258
  			},
  			{
  				nominal: 100,
  				mass: 99.9203488
  			},
  			{
  				nominal: 101,
  				mass: 100.9185862
  			},
  			{
  				nominal: 102,
  				mass: 101.914482
  			},
  			{
  				nominal: 103,
  				mass: 102.9134165
  			},
  			{
  				nominal: 104,
  				mass: 103.9098564
  			},
  			{
  				nominal: 105,
  				mass: 104.9094639
  			},
  			{
  				nominal: 106,
  				mass: 105.9064599,
  				abundance: 0.0125
  			},
  			{
  				nominal: 107,
  				mass: 106.9066121
  			},
  			{
  				nominal: 108,
  				mass: 107.9041834,
  				abundance: 0.0089
  			},
  			{
  				nominal: 109,
  				mass: 108.9049867
  			},
  			{
  				nominal: 110,
  				mass: 109.90300661,
  				abundance: 0.1249
  			},
  			{
  				nominal: 111,
  				mass: 110.90418287,
  				abundance: 0.128
  			},
  			{
  				nominal: 112,
  				mass: 111.90276287,
  				abundance: 0.2413
  			},
  			{
  				nominal: 113,
  				mass: 112.90440813,
  				abundance: 0.1222
  			},
  			{
  				nominal: 114,
  				mass: 113.90336509,
  				abundance: 0.2873
  			},
  			{
  				nominal: 115,
  				mass: 114.90543751
  			},
  			{
  				nominal: 116,
  				mass: 115.90476315,
  				abundance: 0.0749
  			},
  			{
  				nominal: 117,
  				mass: 116.907226
  			},
  			{
  				nominal: 118,
  				mass: 117.906922
  			},
  			{
  				nominal: 119,
  				mass: 118.909847
  			},
  			{
  				nominal: 120,
  				mass: 119.9098681
  			},
  			{
  				nominal: 121,
  				mass: 120.9129637
  			},
  			{
  				nominal: 122,
  				mass: 121.9134591
  			},
  			{
  				nominal: 123,
  				mass: 122.9168925
  			},
  			{
  				nominal: 124,
  				mass: 123.9176574
  			},
  			{
  				nominal: 125,
  				mass: 124.9212576
  			},
  			{
  				nominal: 126,
  				mass: 125.9224291
  			},
  			{
  				nominal: 127,
  				mass: 126.926472
  			},
  			{
  				nominal: 128,
  				mass: 127.9278129
  			},
  			{
  				nominal: 129,
  				mass: 128.93182
  			},
  			{
  				nominal: 130,
  				mass: 129.93394
  			},
  			{
  				nominal: 131,
  				mass: 130.9406
  			},
  			{
  				nominal: 132,
  				mass: 131.94604
  			},
  			{
  				nominal: 133,
  				mass: 132.95285
  			}
  		],
  		symbol: "Cd",
  		mass: 112.411557818268,
  		name: "Cadmium",
  		monoisotopicMass: 113.90336509
  	},
  	{
  		number: 49,
  		isotopes: [
  			{
  				nominal: 97,
  				mass: 96.94934
  			},
  			{
  				nominal: 98,
  				mass: 97.94214
  			},
  			{
  				nominal: 99,
  				mass: 98.93411
  			},
  			{
  				nominal: 100,
  				mass: 99.93096
  			},
  			{
  				nominal: 101,
  				mass: 100.92634
  			},
  			{
  				nominal: 102,
  				mass: 101.9241071
  			},
  			{
  				nominal: 103,
  				mass: 102.9198819
  			},
  			{
  				nominal: 104,
  				mass: 103.9182145
  			},
  			{
  				nominal: 105,
  				mass: 104.914502
  			},
  			{
  				nominal: 106,
  				mass: 105.913464
  			},
  			{
  				nominal: 107,
  				mass: 106.91029
  			},
  			{
  				nominal: 108,
  				mass: 107.9096935
  			},
  			{
  				nominal: 109,
  				mass: 108.9071514
  			},
  			{
  				nominal: 110,
  				mass: 109.90717
  			},
  			{
  				nominal: 111,
  				mass: 110.9051085
  			},
  			{
  				nominal: 112,
  				mass: 111.9055377
  			},
  			{
  				nominal: 113,
  				mass: 112.90406184,
  				abundance: 0.0429
  			},
  			{
  				nominal: 114,
  				mass: 113.90491791
  			},
  			{
  				nominal: 115,
  				mass: 114.903878776,
  				abundance: 0.9571
  			},
  			{
  				nominal: 116,
  				mass: 115.90525999
  			},
  			{
  				nominal: 117,
  				mass: 116.9045157
  			},
  			{
  				nominal: 118,
  				mass: 117.9063566
  			},
  			{
  				nominal: 119,
  				mass: 118.9058507
  			},
  			{
  				nominal: 120,
  				mass: 119.907967
  			},
  			{
  				nominal: 121,
  				mass: 120.907851
  			},
  			{
  				nominal: 122,
  				mass: 121.910281
  			},
  			{
  				nominal: 123,
  				mass: 122.910434
  			},
  			{
  				nominal: 124,
  				mass: 123.913182
  			},
  			{
  				nominal: 125,
  				mass: 124.913605
  			},
  			{
  				nominal: 126,
  				mass: 125.916507
  			},
  			{
  				nominal: 127,
  				mass: 126.917446
  			},
  			{
  				nominal: 128,
  				mass: 127.9204
  			},
  			{
  				nominal: 129,
  				mass: 128.9218053
  			},
  			{
  				nominal: 130,
  				mass: 129.924977
  			},
  			{
  				nominal: 131,
  				mass: 130.9269715
  			},
  			{
  				nominal: 132,
  				mass: 131.933001
  			},
  			{
  				nominal: 133,
  				mass: 132.93831
  			},
  			{
  				nominal: 134,
  				mass: 133.94454
  			},
  			{
  				nominal: 135,
  				mass: 134.95005
  			}
  		],
  		symbol: "In",
  		mass: 114.81808662944559,
  		name: "Indium",
  		monoisotopicMass: 114.903878776
  	},
  	{
  		number: 50,
  		isotopes: [
  			{
  				nominal: 99,
  				mass: 98.94853
  			},
  			{
  				nominal: 100,
  				mass: 99.9385
  			},
  			{
  				nominal: 101,
  				mass: 100.93526
  			},
  			{
  				nominal: 102,
  				mass: 101.93029
  			},
  			{
  				nominal: 103,
  				mass: 102.928105
  			},
  			{
  				nominal: 104,
  				mass: 103.9231052
  			},
  			{
  				nominal: 105,
  				mass: 104.9212684
  			},
  			{
  				nominal: 106,
  				mass: 105.9169574
  			},
  			{
  				nominal: 107,
  				mass: 106.9157137
  			},
  			{
  				nominal: 108,
  				mass: 107.9118943
  			},
  			{
  				nominal: 109,
  				mass: 108.9112921
  			},
  			{
  				nominal: 110,
  				mass: 109.907845
  			},
  			{
  				nominal: 111,
  				mass: 110.9077401
  			},
  			{
  				nominal: 112,
  				mass: 111.90482387,
  				abundance: 0.0097
  			},
  			{
  				nominal: 113,
  				mass: 112.9051757
  			},
  			{
  				nominal: 114,
  				mass: 113.9027827,
  				abundance: 0.0066
  			},
  			{
  				nominal: 115,
  				mass: 114.903344699,
  				abundance: 0.0034
  			},
  			{
  				nominal: 116,
  				mass: 115.9017428,
  				abundance: 0.1454
  			},
  			{
  				nominal: 117,
  				mass: 116.90295398,
  				abundance: 0.0768
  			},
  			{
  				nominal: 118,
  				mass: 117.90160657,
  				abundance: 0.2422
  			},
  			{
  				nominal: 119,
  				mass: 118.90331117,
  				abundance: 0.0859
  			},
  			{
  				nominal: 120,
  				mass: 119.90220163,
  				abundance: 0.3258
  			},
  			{
  				nominal: 121,
  				mass: 120.9042426
  			},
  			{
  				nominal: 122,
  				mass: 121.9034438,
  				abundance: 0.0463
  			},
  			{
  				nominal: 123,
  				mass: 122.9057252
  			},
  			{
  				nominal: 124,
  				mass: 123.9052766,
  				abundance: 0.0579
  			},
  			{
  				nominal: 125,
  				mass: 124.9077864
  			},
  			{
  				nominal: 126,
  				mass: 125.907659
  			},
  			{
  				nominal: 127,
  				mass: 126.91039
  			},
  			{
  				nominal: 128,
  				mass: 127.910507
  			},
  			{
  				nominal: 129,
  				mass: 128.913465
  			},
  			{
  				nominal: 130,
  				mass: 129.9139738
  			},
  			{
  				nominal: 131,
  				mass: 130.917045
  			},
  			{
  				nominal: 132,
  				mass: 131.9178267
  			},
  			{
  				nominal: 133,
  				mass: 132.9239134
  			},
  			{
  				nominal: 134,
  				mass: 133.9286821
  			},
  			{
  				nominal: 135,
  				mass: 134.9349086
  			},
  			{
  				nominal: 136,
  				mass: 135.93999
  			},
  			{
  				nominal: 137,
  				mass: 136.94655
  			},
  			{
  				nominal: 138,
  				mass: 137.95184
  			}
  		],
  		symbol: "Sn",
  		mass: 118.71011259301059,
  		name: "Tin",
  		monoisotopicMass: 119.90220163
  	},
  	{
  		number: 51,
  		isotopes: [
  			{
  				nominal: 103,
  				mass: 102.93969
  			},
  			{
  				nominal: 104,
  				mass: 103.93648
  			},
  			{
  				nominal: 105,
  				mass: 104.931276
  			},
  			{
  				nominal: 106,
  				mass: 105.928638
  			},
  			{
  				nominal: 107,
  				mass: 106.9241506
  			},
  			{
  				nominal: 108,
  				mass: 107.9222267
  			},
  			{
  				nominal: 109,
  				mass: 108.9181411
  			},
  			{
  				nominal: 110,
  				mass: 109.9168543
  			},
  			{
  				nominal: 111,
  				mass: 110.9132182
  			},
  			{
  				nominal: 112,
  				mass: 111.9124
  			},
  			{
  				nominal: 113,
  				mass: 112.909375
  			},
  			{
  				nominal: 114,
  				mass: 113.90929
  			},
  			{
  				nominal: 115,
  				mass: 114.906598
  			},
  			{
  				nominal: 116,
  				mass: 115.9067931
  			},
  			{
  				nominal: 117,
  				mass: 116.9048415
  			},
  			{
  				nominal: 118,
  				mass: 117.9055321
  			},
  			{
  				nominal: 119,
  				mass: 118.9039455
  			},
  			{
  				nominal: 120,
  				mass: 119.9050794
  			},
  			{
  				nominal: 121,
  				mass: 120.903812,
  				abundance: 0.5721
  			},
  			{
  				nominal: 122,
  				mass: 121.9051699
  			},
  			{
  				nominal: 123,
  				mass: 122.9042132,
  				abundance: 0.4279
  			},
  			{
  				nominal: 124,
  				mass: 123.905935
  			},
  			{
  				nominal: 125,
  				mass: 124.905253
  			},
  			{
  				nominal: 126,
  				mass: 125.907253
  			},
  			{
  				nominal: 127,
  				mass: 126.9069243
  			},
  			{
  				nominal: 128,
  				mass: 127.909146
  			},
  			{
  				nominal: 129,
  				mass: 128.909147
  			},
  			{
  				nominal: 130,
  				mass: 129.911662
  			},
  			{
  				nominal: 131,
  				mass: 130.9119888
  			},
  			{
  				nominal: 132,
  				mass: 131.9145077
  			},
  			{
  				nominal: 133,
  				mass: 132.9152732
  			},
  			{
  				nominal: 134,
  				mass: 133.9205357
  			},
  			{
  				nominal: 135,
  				mass: 134.9251851
  			},
  			{
  				nominal: 136,
  				mass: 135.9307459
  			},
  			{
  				nominal: 137,
  				mass: 136.93555
  			},
  			{
  				nominal: 138,
  				mass: 137.94145
  			},
  			{
  				nominal: 139,
  				mass: 138.94655
  			},
  			{
  				nominal: 140,
  				mass: 139.95283
  			}
  		],
  		symbol: "Sb",
  		mass: 121.75978367348,
  		name: "Antimony",
  		monoisotopicMass: 120.903812
  	},
  	{
  		number: 52,
  		isotopes: [
  			{
  				nominal: 105,
  				mass: 104.9433
  			},
  			{
  				nominal: 106,
  				mass: 105.9375
  			},
  			{
  				nominal: 107,
  				mass: 106.935012
  			},
  			{
  				nominal: 108,
  				mass: 107.9293805
  			},
  			{
  				nominal: 109,
  				mass: 108.9273045
  			},
  			{
  				nominal: 110,
  				mass: 109.9224581
  			},
  			{
  				nominal: 111,
  				mass: 110.9210006
  			},
  			{
  				nominal: 112,
  				mass: 111.9167279
  			},
  			{
  				nominal: 113,
  				mass: 112.915891
  			},
  			{
  				nominal: 114,
  				mass: 113.912089
  			},
  			{
  				nominal: 115,
  				mass: 114.911902
  			},
  			{
  				nominal: 116,
  				mass: 115.90846
  			},
  			{
  				nominal: 117,
  				mass: 116.908646
  			},
  			{
  				nominal: 118,
  				mass: 117.905854
  			},
  			{
  				nominal: 119,
  				mass: 118.9064071
  			},
  			{
  				nominal: 120,
  				mass: 119.9040593,
  				abundance: 0.0009
  			},
  			{
  				nominal: 121,
  				mass: 120.904944
  			},
  			{
  				nominal: 122,
  				mass: 121.9030435,
  				abundance: 0.0255
  			},
  			{
  				nominal: 123,
  				mass: 122.9042698,
  				abundance: 0.0089
  			},
  			{
  				nominal: 124,
  				mass: 123.9028171,
  				abundance: 0.0474
  			},
  			{
  				nominal: 125,
  				mass: 124.9044299,
  				abundance: 0.0707
  			},
  			{
  				nominal: 126,
  				mass: 125.9033109,
  				abundance: 0.1884
  			},
  			{
  				nominal: 127,
  				mass: 126.9052257
  			},
  			{
  				nominal: 128,
  				mass: 127.90446128,
  				abundance: 0.3174
  			},
  			{
  				nominal: 129,
  				mass: 128.90659646
  			},
  			{
  				nominal: 130,
  				mass: 129.906222748,
  				abundance: 0.3408
  			},
  			{
  				nominal: 131,
  				mass: 130.908522213
  			},
  			{
  				nominal: 132,
  				mass: 131.9085467
  			},
  			{
  				nominal: 133,
  				mass: 132.9109688
  			},
  			{
  				nominal: 134,
  				mass: 133.911394
  			},
  			{
  				nominal: 135,
  				mass: 134.9165557
  			},
  			{
  				nominal: 136,
  				mass: 135.9201006
  			},
  			{
  				nominal: 137,
  				mass: 136.9255989
  			},
  			{
  				nominal: 138,
  				mass: 137.9294722
  			},
  			{
  				nominal: 139,
  				mass: 138.9353672
  			},
  			{
  				nominal: 140,
  				mass: 139.939499
  			},
  			{
  				nominal: 141,
  				mass: 140.9458
  			},
  			{
  				nominal: 142,
  				mass: 141.95022
  			},
  			{
  				nominal: 143,
  				mass: 142.95676
  			}
  		],
  		symbol: "Te",
  		mass: 127.6031264846604,
  		name: "Tellurium",
  		monoisotopicMass: 129.906222748
  	},
  	{
  		number: 53,
  		isotopes: [
  			{
  				nominal: 107,
  				mass: 106.94678
  			},
  			{
  				nominal: 108,
  				mass: 107.94348
  			},
  			{
  				nominal: 109,
  				mass: 108.9380853
  			},
  			{
  				nominal: 110,
  				mass: 109.935089
  			},
  			{
  				nominal: 111,
  				mass: 110.9302692
  			},
  			{
  				nominal: 112,
  				mass: 111.928005
  			},
  			{
  				nominal: 113,
  				mass: 112.9236501
  			},
  			{
  				nominal: 114,
  				mass: 113.92185
  			},
  			{
  				nominal: 115,
  				mass: 114.918048
  			},
  			{
  				nominal: 116,
  				mass: 115.91681
  			},
  			{
  				nominal: 117,
  				mass: 116.913648
  			},
  			{
  				nominal: 118,
  				mass: 117.913074
  			},
  			{
  				nominal: 119,
  				mass: 118.910074
  			},
  			{
  				nominal: 120,
  				mass: 119.910087
  			},
  			{
  				nominal: 121,
  				mass: 120.9074051
  			},
  			{
  				nominal: 122,
  				mass: 121.9075888
  			},
  			{
  				nominal: 123,
  				mass: 122.9055885
  			},
  			{
  				nominal: 124,
  				mass: 123.906209
  			},
  			{
  				nominal: 125,
  				mass: 124.9046294
  			},
  			{
  				nominal: 126,
  				mass: 125.9056233
  			},
  			{
  				nominal: 127,
  				mass: 126.9044719,
  				abundance: 1
  			},
  			{
  				nominal: 128,
  				mass: 127.9058086
  			},
  			{
  				nominal: 129,
  				mass: 128.9049837
  			},
  			{
  				nominal: 130,
  				mass: 129.9066702
  			},
  			{
  				nominal: 131,
  				mass: 130.9061263
  			},
  			{
  				nominal: 132,
  				mass: 131.9079935
  			},
  			{
  				nominal: 133,
  				mass: 132.907797
  			},
  			{
  				nominal: 134,
  				mass: 133.9097588
  			},
  			{
  				nominal: 135,
  				mass: 134.9100488
  			},
  			{
  				nominal: 136,
  				mass: 135.914604
  			},
  			{
  				nominal: 137,
  				mass: 136.9180282
  			},
  			{
  				nominal: 138,
  				mass: 137.9227264
  			},
  			{
  				nominal: 139,
  				mass: 138.926506
  			},
  			{
  				nominal: 140,
  				mass: 139.93173
  			},
  			{
  				nominal: 141,
  				mass: 140.93569
  			},
  			{
  				nominal: 142,
  				mass: 141.9412
  			},
  			{
  				nominal: 143,
  				mass: 142.94565
  			},
  			{
  				nominal: 144,
  				mass: 143.95139
  			},
  			{
  				nominal: 145,
  				mass: 144.95605
  			}
  		],
  		symbol: "I",
  		mass: 126.9044719,
  		name: "Iodine",
  		monoisotopicMass: 126.9044719
  	},
  	{
  		number: 54,
  		isotopes: [
  			{
  				nominal: 109,
  				mass: 108.95043
  			},
  			{
  				nominal: 110,
  				mass: 109.94426
  			},
  			{
  				nominal: 111,
  				mass: 110.941607
  			},
  			{
  				nominal: 112,
  				mass: 111.935559
  			},
  			{
  				nominal: 113,
  				mass: 112.9332217
  			},
  			{
  				nominal: 114,
  				mass: 113.92798
  			},
  			{
  				nominal: 115,
  				mass: 114.926294
  			},
  			{
  				nominal: 116,
  				mass: 115.921581
  			},
  			{
  				nominal: 117,
  				mass: 116.920359
  			},
  			{
  				nominal: 118,
  				mass: 117.916179
  			},
  			{
  				nominal: 119,
  				mass: 118.915411
  			},
  			{
  				nominal: 120,
  				mass: 119.911784
  			},
  			{
  				nominal: 121,
  				mass: 120.911453
  			},
  			{
  				nominal: 122,
  				mass: 121.908368
  			},
  			{
  				nominal: 123,
  				mass: 122.908482
  			},
  			{
  				nominal: 124,
  				mass: 123.905892,
  				abundance: 0.000952
  			},
  			{
  				nominal: 125,
  				mass: 124.9063944
  			},
  			{
  				nominal: 126,
  				mass: 125.9042983,
  				abundance: 0.00089
  			},
  			{
  				nominal: 127,
  				mass: 126.9051829
  			},
  			{
  				nominal: 128,
  				mass: 127.903531,
  				abundance: 0.019102
  			},
  			{
  				nominal: 129,
  				mass: 128.9047808611,
  				abundance: 0.264006
  			},
  			{
  				nominal: 130,
  				mass: 129.903509349,
  				abundance: 0.04071
  			},
  			{
  				nominal: 131,
  				mass: 130.90508406,
  				abundance: 0.212324
  			},
  			{
  				nominal: 132,
  				mass: 131.9041550856,
  				abundance: 0.269086
  			},
  			{
  				nominal: 133,
  				mass: 132.9059108
  			},
  			{
  				nominal: 134,
  				mass: 133.90539466,
  				abundance: 0.104357
  			},
  			{
  				nominal: 135,
  				mass: 134.9072278
  			},
  			{
  				nominal: 136,
  				mass: 135.907214484,
  				abundance: 0.088573
  			},
  			{
  				nominal: 137,
  				mass: 136.91155778
  			},
  			{
  				nominal: 138,
  				mass: 137.9141463
  			},
  			{
  				nominal: 139,
  				mass: 138.9187922
  			},
  			{
  				nominal: 140,
  				mass: 139.9216458
  			},
  			{
  				nominal: 141,
  				mass: 140.9267872
  			},
  			{
  				nominal: 142,
  				mass: 141.9299731
  			},
  			{
  				nominal: 143,
  				mass: 142.9353696
  			},
  			{
  				nominal: 144,
  				mass: 143.9389451
  			},
  			{
  				nominal: 145,
  				mass: 144.94472
  			},
  			{
  				nominal: 146,
  				mass: 145.948518
  			},
  			{
  				nominal: 147,
  				mass: 146.95426
  			},
  			{
  				nominal: 148,
  				mass: 147.95813
  			}
  		],
  		symbol: "Xe",
  		mass: 131.29276144779053,
  		name: "Xenon",
  		monoisotopicMass: 131.9041550856
  	},
  	{
  		number: 55,
  		isotopes: [
  			{
  				nominal: 112,
  				mass: 111.950309
  			},
  			{
  				nominal: 113,
  				mass: 112.9444291
  			},
  			{
  				nominal: 114,
  				mass: 113.941296
  			},
  			{
  				nominal: 115,
  				mass: 114.93591
  			},
  			{
  				nominal: 116,
  				mass: 115.93337
  			},
  			{
  				nominal: 117,
  				mass: 116.928617
  			},
  			{
  				nominal: 118,
  				mass: 117.92656
  			},
  			{
  				nominal: 119,
  				mass: 118.922377
  			},
  			{
  				nominal: 120,
  				mass: 119.920677
  			},
  			{
  				nominal: 121,
  				mass: 120.917227
  			},
  			{
  				nominal: 122,
  				mass: 121.916108
  			},
  			{
  				nominal: 123,
  				mass: 122.912996
  			},
  			{
  				nominal: 124,
  				mass: 123.9122578
  			},
  			{
  				nominal: 125,
  				mass: 124.909728
  			},
  			{
  				nominal: 126,
  				mass: 125.909446
  			},
  			{
  				nominal: 127,
  				mass: 126.9074174
  			},
  			{
  				nominal: 128,
  				mass: 127.9077487
  			},
  			{
  				nominal: 129,
  				mass: 128.9060657
  			},
  			{
  				nominal: 130,
  				mass: 129.9067093
  			},
  			{
  				nominal: 131,
  				mass: 130.9054649
  			},
  			{
  				nominal: 132,
  				mass: 131.9064339
  			},
  			{
  				nominal: 133,
  				mass: 132.905451961,
  				abundance: 1
  			},
  			{
  				nominal: 134,
  				mass: 133.906718503
  			},
  			{
  				nominal: 135,
  				mass: 134.905977
  			},
  			{
  				nominal: 136,
  				mass: 135.9073114
  			},
  			{
  				nominal: 137,
  				mass: 136.90708923
  			},
  			{
  				nominal: 138,
  				mass: 137.9110171
  			},
  			{
  				nominal: 139,
  				mass: 138.9133638
  			},
  			{
  				nominal: 140,
  				mass: 139.9172831
  			},
  			{
  				nominal: 141,
  				mass: 140.9200455
  			},
  			{
  				nominal: 142,
  				mass: 141.924296
  			},
  			{
  				nominal: 143,
  				mass: 142.927349
  			},
  			{
  				nominal: 144,
  				mass: 143.932076
  			},
  			{
  				nominal: 145,
  				mass: 144.935527
  			},
  			{
  				nominal: 146,
  				mass: 145.940344
  			},
  			{
  				nominal: 147,
  				mass: 146.944156
  			},
  			{
  				nominal: 148,
  				mass: 147.94923
  			},
  			{
  				nominal: 149,
  				mass: 148.95302
  			},
  			{
  				nominal: 150,
  				mass: 149.95833
  			},
  			{
  				nominal: 151,
  				mass: 150.96258
  			}
  		],
  		symbol: "Cs",
  		mass: 132.905451961,
  		name: "Caesium",
  		monoisotopicMass: 132.905451961
  	},
  	{
  		number: 56,
  		isotopes: [
  			{
  				nominal: 114,
  				mass: 113.95066
  			},
  			{
  				nominal: 115,
  				mass: 114.94737
  			},
  			{
  				nominal: 116,
  				mass: 115.94128
  			},
  			{
  				nominal: 117,
  				mass: 116.93814
  			},
  			{
  				nominal: 118,
  				mass: 117.93306
  			},
  			{
  				nominal: 119,
  				mass: 118.93066
  			},
  			{
  				nominal: 120,
  				mass: 119.92605
  			},
  			{
  				nominal: 121,
  				mass: 120.92405
  			},
  			{
  				nominal: 122,
  				mass: 121.919904
  			},
  			{
  				nominal: 123,
  				mass: 122.918781
  			},
  			{
  				nominal: 124,
  				mass: 123.915094
  			},
  			{
  				nominal: 125,
  				mass: 124.914472
  			},
  			{
  				nominal: 126,
  				mass: 125.91125
  			},
  			{
  				nominal: 127,
  				mass: 126.911091
  			},
  			{
  				nominal: 128,
  				mass: 127.908342
  			},
  			{
  				nominal: 129,
  				mass: 128.908681
  			},
  			{
  				nominal: 130,
  				mass: 129.9063207,
  				abundance: 0.00106
  			},
  			{
  				nominal: 131,
  				mass: 130.906941
  			},
  			{
  				nominal: 132,
  				mass: 131.9050611,
  				abundance: 0.00101
  			},
  			{
  				nominal: 133,
  				mass: 132.9060074
  			},
  			{
  				nominal: 134,
  				mass: 133.90450818,
  				abundance: 0.02417
  			},
  			{
  				nominal: 135,
  				mass: 134.90568838,
  				abundance: 0.06592
  			},
  			{
  				nominal: 136,
  				mass: 135.90457573,
  				abundance: 0.07854
  			},
  			{
  				nominal: 137,
  				mass: 136.90582714,
  				abundance: 0.11232
  			},
  			{
  				nominal: 138,
  				mass: 137.905247,
  				abundance: 0.71698
  			},
  			{
  				nominal: 139,
  				mass: 138.9088411
  			},
  			{
  				nominal: 140,
  				mass: 139.9106057
  			},
  			{
  				nominal: 141,
  				mass: 140.9144033
  			},
  			{
  				nominal: 142,
  				mass: 141.9164324
  			},
  			{
  				nominal: 143,
  				mass: 142.9206253
  			},
  			{
  				nominal: 144,
  				mass: 143.9229549
  			},
  			{
  				nominal: 145,
  				mass: 144.9275184
  			},
  			{
  				nominal: 146,
  				mass: 145.930284
  			},
  			{
  				nominal: 147,
  				mass: 146.935304
  			},
  			{
  				nominal: 148,
  				mass: 147.938171
  			},
  			{
  				nominal: 149,
  				mass: 148.94308
  			},
  			{
  				nominal: 150,
  				mass: 149.94605
  			},
  			{
  				nominal: 151,
  				mass: 150.95127
  			},
  			{
  				nominal: 152,
  				mass: 151.95481
  			},
  			{
  				nominal: 153,
  				mass: 152.96036
  			}
  		],
  		symbol: "Ba",
  		mass: 137.3268916286322,
  		name: "Barium",
  		monoisotopicMass: 137.905247
  	},
  	{
  		number: 57,
  		isotopes: [
  			{
  				nominal: 116,
  				mass: 115.9563
  			},
  			{
  				nominal: 117,
  				mass: 116.94999
  			},
  			{
  				nominal: 118,
  				mass: 117.94673
  			},
  			{
  				nominal: 119,
  				mass: 118.94099
  			},
  			{
  				nominal: 120,
  				mass: 119.93807
  			},
  			{
  				nominal: 121,
  				mass: 120.93315
  			},
  			{
  				nominal: 122,
  				mass: 121.93071
  			},
  			{
  				nominal: 123,
  				mass: 122.9263
  			},
  			{
  				nominal: 124,
  				mass: 123.924574
  			},
  			{
  				nominal: 125,
  				mass: 124.920816
  			},
  			{
  				nominal: 126,
  				mass: 125.919513
  			},
  			{
  				nominal: 127,
  				mass: 126.916375
  			},
  			{
  				nominal: 128,
  				mass: 127.915592
  			},
  			{
  				nominal: 129,
  				mass: 128.912694
  			},
  			{
  				nominal: 130,
  				mass: 129.912369
  			},
  			{
  				nominal: 131,
  				mass: 130.91007
  			},
  			{
  				nominal: 132,
  				mass: 131.910119
  			},
  			{
  				nominal: 133,
  				mass: 132.908218
  			},
  			{
  				nominal: 134,
  				mass: 133.908514
  			},
  			{
  				nominal: 135,
  				mass: 134.906984
  			},
  			{
  				nominal: 136,
  				mass: 135.907635
  			},
  			{
  				nominal: 137,
  				mass: 136.9064504
  			},
  			{
  				nominal: 138,
  				mass: 137.9071149,
  				abundance: 0.0008881
  			},
  			{
  				nominal: 139,
  				mass: 138.9063563,
  				abundance: 0.9991119
  			},
  			{
  				nominal: 140,
  				mass: 139.9094806
  			},
  			{
  				nominal: 141,
  				mass: 140.910966
  			},
  			{
  				nominal: 142,
  				mass: 141.9140909
  			},
  			{
  				nominal: 143,
  				mass: 142.9160795
  			},
  			{
  				nominal: 144,
  				mass: 143.919646
  			},
  			{
  				nominal: 145,
  				mass: 144.921808
  			},
  			{
  				nominal: 146,
  				mass: 145.925875
  			},
  			{
  				nominal: 147,
  				mass: 146.928418
  			},
  			{
  				nominal: 148,
  				mass: 147.932679
  			},
  			{
  				nominal: 149,
  				mass: 148.93535
  			},
  			{
  				nominal: 150,
  				mass: 149.93947
  			},
  			{
  				nominal: 151,
  				mass: 150.94232
  			},
  			{
  				nominal: 152,
  				mass: 151.94682
  			},
  			{
  				nominal: 153,
  				mass: 152.95036
  			},
  			{
  				nominal: 154,
  				mass: 153.95517
  			},
  			{
  				nominal: 155,
  				mass: 154.95901
  			}
  		],
  		symbol: "La",
  		mass: 138.90546887371266,
  		name: "Lanthanum",
  		monoisotopicMass: 138.9063563
  	},
  	{
  		number: 58,
  		isotopes: [
  			{
  				nominal: 119,
  				mass: 118.95271
  			},
  			{
  				nominal: 120,
  				mass: 119.94654
  			},
  			{
  				nominal: 121,
  				mass: 120.94335
  			},
  			{
  				nominal: 122,
  				mass: 121.93787
  			},
  			{
  				nominal: 123,
  				mass: 122.93528
  			},
  			{
  				nominal: 124,
  				mass: 123.93031
  			},
  			{
  				nominal: 125,
  				mass: 124.92844
  			},
  			{
  				nominal: 126,
  				mass: 125.923971
  			},
  			{
  				nominal: 127,
  				mass: 126.922727
  			},
  			{
  				nominal: 128,
  				mass: 127.918911
  			},
  			{
  				nominal: 129,
  				mass: 128.918102
  			},
  			{
  				nominal: 130,
  				mass: 129.914736
  			},
  			{
  				nominal: 131,
  				mass: 130.914429
  			},
  			{
  				nominal: 132,
  				mass: 131.911464
  			},
  			{
  				nominal: 133,
  				mass: 132.91152
  			},
  			{
  				nominal: 134,
  				mass: 133.908928
  			},
  			{
  				nominal: 135,
  				mass: 134.909161
  			},
  			{
  				nominal: 136,
  				mass: 135.90712921,
  				abundance: 0.00185
  			},
  			{
  				nominal: 137,
  				mass: 136.90776236
  			},
  			{
  				nominal: 138,
  				mass: 137.905991,
  				abundance: 0.00251
  			},
  			{
  				nominal: 139,
  				mass: 138.9066551
  			},
  			{
  				nominal: 140,
  				mass: 139.9054431,
  				abundance: 0.8845
  			},
  			{
  				nominal: 141,
  				mass: 140.9082807
  			},
  			{
  				nominal: 142,
  				mass: 141.9092504,
  				abundance: 0.11114
  			},
  			{
  				nominal: 143,
  				mass: 142.9123921
  			},
  			{
  				nominal: 144,
  				mass: 143.9136529
  			},
  			{
  				nominal: 145,
  				mass: 144.917265
  			},
  			{
  				nominal: 146,
  				mass: 145.918802
  			},
  			{
  				nominal: 147,
  				mass: 146.9226899
  			},
  			{
  				nominal: 148,
  				mass: 147.924424
  			},
  			{
  				nominal: 149,
  				mass: 148.928427
  			},
  			{
  				nominal: 150,
  				mass: 149.930384
  			},
  			{
  				nominal: 151,
  				mass: 150.934272
  			},
  			{
  				nominal: 152,
  				mass: 151.9366
  			},
  			{
  				nominal: 153,
  				mass: 152.94093
  			},
  			{
  				nominal: 154,
  				mass: 153.9438
  			},
  			{
  				nominal: 155,
  				mass: 154.94855
  			},
  			{
  				nominal: 156,
  				mass: 155.95183
  			},
  			{
  				nominal: 157,
  				mass: 156.95705
  			}
  		],
  		symbol: "Ce",
  		mass: 140.1157307378545,
  		name: "Cerium",
  		monoisotopicMass: 139.9054431
  	},
  	{
  		number: 59,
  		isotopes: [
  			{
  				nominal: 121,
  				mass: 120.95532
  			},
  			{
  				nominal: 122,
  				mass: 121.95175
  			},
  			{
  				nominal: 123,
  				mass: 122.94596
  			},
  			{
  				nominal: 124,
  				mass: 123.94294
  			},
  			{
  				nominal: 125,
  				mass: 124.9377
  			},
  			{
  				nominal: 126,
  				mass: 125.93524
  			},
  			{
  				nominal: 127,
  				mass: 126.93071
  			},
  			{
  				nominal: 128,
  				mass: 127.928791
  			},
  			{
  				nominal: 129,
  				mass: 128.925095
  			},
  			{
  				nominal: 130,
  				mass: 129.92359
  			},
  			{
  				nominal: 131,
  				mass: 130.920235
  			},
  			{
  				nominal: 132,
  				mass: 131.919255
  			},
  			{
  				nominal: 133,
  				mass: 132.916331
  			},
  			{
  				nominal: 134,
  				mass: 133.915697
  			},
  			{
  				nominal: 135,
  				mass: 134.913112
  			},
  			{
  				nominal: 136,
  				mass: 135.912677
  			},
  			{
  				nominal: 137,
  				mass: 136.9106792
  			},
  			{
  				nominal: 138,
  				mass: 137.910754
  			},
  			{
  				nominal: 139,
  				mass: 138.9089408
  			},
  			{
  				nominal: 140,
  				mass: 139.9090803
  			},
  			{
  				nominal: 141,
  				mass: 140.9076576,
  				abundance: 1
  			},
  			{
  				nominal: 142,
  				mass: 141.9100496
  			},
  			{
  				nominal: 143,
  				mass: 142.9108228
  			},
  			{
  				nominal: 144,
  				mass: 143.9133109
  			},
  			{
  				nominal: 145,
  				mass: 144.9145182
  			},
  			{
  				nominal: 146,
  				mass: 145.91768
  			},
  			{
  				nominal: 147,
  				mass: 146.919008
  			},
  			{
  				nominal: 148,
  				mass: 147.92213
  			},
  			{
  				nominal: 149,
  				mass: 148.923736
  			},
  			{
  				nominal: 150,
  				mass: 149.9266765
  			},
  			{
  				nominal: 151,
  				mass: 150.928309
  			},
  			{
  				nominal: 152,
  				mass: 151.931553
  			},
  			{
  				nominal: 153,
  				mass: 152.933904
  			},
  			{
  				nominal: 154,
  				mass: 153.93753
  			},
  			{
  				nominal: 155,
  				mass: 154.940509
  			},
  			{
  				nominal: 156,
  				mass: 155.94464
  			},
  			{
  				nominal: 157,
  				mass: 156.94789
  			},
  			{
  				nominal: 158,
  				mass: 157.95241
  			},
  			{
  				nominal: 159,
  				mass: 158.95589
  			}
  		],
  		symbol: "Pr",
  		mass: 140.9076576,
  		name: "Praseodymium",
  		monoisotopicMass: 140.9076576
  	},
  	{
  		number: 60,
  		isotopes: [
  			{
  				nominal: 124,
  				mass: 123.9522
  			},
  			{
  				nominal: 125,
  				mass: 124.9489
  			},
  			{
  				nominal: 126,
  				mass: 125.94311
  			},
  			{
  				nominal: 127,
  				mass: 126.94038
  			},
  			{
  				nominal: 128,
  				mass: 127.93525
  			},
  			{
  				nominal: 129,
  				mass: 128.9331
  			},
  			{
  				nominal: 130,
  				mass: 129.928506
  			},
  			{
  				nominal: 131,
  				mass: 130.927248
  			},
  			{
  				nominal: 132,
  				mass: 131.923321
  			},
  			{
  				nominal: 133,
  				mass: 132.922348
  			},
  			{
  				nominal: 134,
  				mass: 133.91879
  			},
  			{
  				nominal: 135,
  				mass: 134.918181
  			},
  			{
  				nominal: 136,
  				mass: 135.914976
  			},
  			{
  				nominal: 137,
  				mass: 136.914562
  			},
  			{
  				nominal: 138,
  				mass: 137.91195
  			},
  			{
  				nominal: 139,
  				mass: 138.911954
  			},
  			{
  				nominal: 140,
  				mass: 139.90955
  			},
  			{
  				nominal: 141,
  				mass: 140.9096147
  			},
  			{
  				nominal: 142,
  				mass: 141.907729,
  				abundance: 0.27152
  			},
  			{
  				nominal: 143,
  				mass: 142.90982,
  				abundance: 0.12174
  			},
  			{
  				nominal: 144,
  				mass: 143.910093,
  				abundance: 0.23798
  			},
  			{
  				nominal: 145,
  				mass: 144.9125793,
  				abundance: 0.08293
  			},
  			{
  				nominal: 146,
  				mass: 145.9131226,
  				abundance: 0.17189
  			},
  			{
  				nominal: 147,
  				mass: 146.9161061
  			},
  			{
  				nominal: 148,
  				mass: 147.9168993,
  				abundance: 0.05756
  			},
  			{
  				nominal: 149,
  				mass: 148.9201548
  			},
  			{
  				nominal: 150,
  				mass: 149.9209022,
  				abundance: 0.05638
  			},
  			{
  				nominal: 151,
  				mass: 150.9238403
  			},
  			{
  				nominal: 152,
  				mass: 151.924692
  			},
  			{
  				nominal: 153,
  				mass: 152.927718
  			},
  			{
  				nominal: 154,
  				mass: 153.92948
  			},
  			{
  				nominal: 155,
  				mass: 154.9331357
  			},
  			{
  				nominal: 156,
  				mass: 155.93508
  			},
  			{
  				nominal: 157,
  				mass: 156.939386
  			},
  			{
  				nominal: 158,
  				mass: 157.94197
  			},
  			{
  				nominal: 159,
  				mass: 158.94653
  			},
  			{
  				nominal: 160,
  				mass: 159.9494
  			},
  			{
  				nominal: 161,
  				mass: 160.95428
  			}
  		],
  		symbol: "Nd",
  		mass: 144.241596031827,
  		name: "Neodymium",
  		monoisotopicMass: 141.907729
  	},
  	{
  		number: 61,
  		isotopes: [
  			{
  				nominal: 126,
  				mass: 125.95792
  			},
  			{
  				nominal: 127,
  				mass: 126.95192
  			},
  			{
  				nominal: 128,
  				mass: 127.9487
  			},
  			{
  				nominal: 129,
  				mass: 128.94323
  			},
  			{
  				nominal: 130,
  				mass: 129.94053
  			},
  			{
  				nominal: 131,
  				mass: 130.93567
  			},
  			{
  				nominal: 132,
  				mass: 131.93384
  			},
  			{
  				nominal: 133,
  				mass: 132.929782
  			},
  			{
  				nominal: 134,
  				mass: 133.928353
  			},
  			{
  				nominal: 135,
  				mass: 134.924823
  			},
  			{
  				nominal: 136,
  				mass: 135.923585
  			},
  			{
  				nominal: 137,
  				mass: 136.92048
  			},
  			{
  				nominal: 138,
  				mass: 137.919548
  			},
  			{
  				nominal: 139,
  				mass: 138.9168
  			},
  			{
  				nominal: 140,
  				mass: 139.91604
  			},
  			{
  				nominal: 141,
  				mass: 140.913555
  			},
  			{
  				nominal: 142,
  				mass: 141.91289
  			},
  			{
  				nominal: 143,
  				mass: 142.9109383
  			},
  			{
  				nominal: 144,
  				mass: 143.9125964
  			},
  			{
  				nominal: 145,
  				mass: 144.9127559
  			},
  			{
  				nominal: 146,
  				mass: 145.9147024
  			},
  			{
  				nominal: 147,
  				mass: 146.915145
  			},
  			{
  				nominal: 148,
  				mass: 147.9174819
  			},
  			{
  				nominal: 149,
  				mass: 148.9183423
  			},
  			{
  				nominal: 150,
  				mass: 149.920991
  			},
  			{
  				nominal: 151,
  				mass: 150.9212175
  			},
  			{
  				nominal: 152,
  				mass: 151.923506
  			},
  			{
  				nominal: 153,
  				mass: 152.9241567
  			},
  			{
  				nominal: 154,
  				mass: 153.926472
  			},
  			{
  				nominal: 155,
  				mass: 154.928137
  			},
  			{
  				nominal: 156,
  				mass: 155.9311175
  			},
  			{
  				nominal: 157,
  				mass: 156.9331214
  			},
  			{
  				nominal: 158,
  				mass: 157.936565
  			},
  			{
  				nominal: 159,
  				mass: 158.939287
  			},
  			{
  				nominal: 160,
  				mass: 159.9431
  			},
  			{
  				nominal: 161,
  				mass: 160.94607
  			},
  			{
  				nominal: 162,
  				mass: 161.95022
  			},
  			{
  				nominal: 163,
  				mass: 162.95357
  			}
  		],
  		symbol: "Pm",
  		mass: null,
  		name: "Promethium"
  	},
  	{
  		number: 62,
  		isotopes: [
  			{
  				nominal: 128,
  				mass: 127.95842
  			},
  			{
  				nominal: 129,
  				mass: 128.95476
  			},
  			{
  				nominal: 130,
  				mass: 129.949
  			},
  			{
  				nominal: 131,
  				mass: 130.94618
  			},
  			{
  				nominal: 132,
  				mass: 131.94087
  			},
  			{
  				nominal: 133,
  				mass: 132.93856
  			},
  			{
  				nominal: 134,
  				mass: 133.93411
  			},
  			{
  				nominal: 135,
  				mass: 134.93252
  			},
  			{
  				nominal: 136,
  				mass: 135.928276
  			},
  			{
  				nominal: 137,
  				mass: 136.926971
  			},
  			{
  				nominal: 138,
  				mass: 137.923244
  			},
  			{
  				nominal: 139,
  				mass: 138.922297
  			},
  			{
  				nominal: 140,
  				mass: 139.918995
  			},
  			{
  				nominal: 141,
  				mass: 140.9184816
  			},
  			{
  				nominal: 142,
  				mass: 141.9152044
  			},
  			{
  				nominal: 143,
  				mass: 142.9146353
  			},
  			{
  				nominal: 144,
  				mass: 143.9120065,
  				abundance: 0.0307
  			},
  			{
  				nominal: 145,
  				mass: 144.9134173
  			},
  			{
  				nominal: 146,
  				mass: 145.913047
  			},
  			{
  				nominal: 147,
  				mass: 146.9149044,
  				abundance: 0.1499
  			},
  			{
  				nominal: 148,
  				mass: 147.9148292,
  				abundance: 0.1124
  			},
  			{
  				nominal: 149,
  				mass: 148.9171921,
  				abundance: 0.1382
  			},
  			{
  				nominal: 150,
  				mass: 149.9172829,
  				abundance: 0.0738
  			},
  			{
  				nominal: 151,
  				mass: 150.9199398
  			},
  			{
  				nominal: 152,
  				mass: 151.9197397,
  				abundance: 0.2675
  			},
  			{
  				nominal: 153,
  				mass: 152.9221047
  			},
  			{
  				nominal: 154,
  				mass: 153.9222169,
  				abundance: 0.2275
  			},
  			{
  				nominal: 155,
  				mass: 154.9246477
  			},
  			{
  				nominal: 156,
  				mass: 155.925536
  			},
  			{
  				nominal: 157,
  				mass: 156.9284187
  			},
  			{
  				nominal: 158,
  				mass: 157.929951
  			},
  			{
  				nominal: 159,
  				mass: 158.9332172
  			},
  			{
  				nominal: 160,
  				mass: 159.9353353
  			},
  			{
  				nominal: 161,
  				mass: 160.9391602
  			},
  			{
  				nominal: 162,
  				mass: 161.94146
  			},
  			{
  				nominal: 163,
  				mass: 162.94555
  			},
  			{
  				nominal: 164,
  				mass: 163.94836
  			},
  			{
  				nominal: 165,
  				mass: 164.95297
  			}
  		],
  		symbol: "Sm",
  		mass: 150.36635571193,
  		name: "Samarium",
  		monoisotopicMass: 151.9197397
  	},
  	{
  		number: 63,
  		isotopes: [
  			{
  				nominal: 130,
  				mass: 129.96369
  			},
  			{
  				nominal: 131,
  				mass: 130.95784
  			},
  			{
  				nominal: 132,
  				mass: 131.95467
  			},
  			{
  				nominal: 133,
  				mass: 132.94929
  			},
  			{
  				nominal: 134,
  				mass: 133.9464
  			},
  			{
  				nominal: 135,
  				mass: 134.94187
  			},
  			{
  				nominal: 136,
  				mass: 135.93962
  			},
  			{
  				nominal: 137,
  				mass: 136.93546
  			},
  			{
  				nominal: 138,
  				mass: 137.933709
  			},
  			{
  				nominal: 139,
  				mass: 138.929792
  			},
  			{
  				nominal: 140,
  				mass: 139.928088
  			},
  			{
  				nominal: 141,
  				mass: 140.924932
  			},
  			{
  				nominal: 142,
  				mass: 141.923442
  			},
  			{
  				nominal: 143,
  				mass: 142.920299
  			},
  			{
  				nominal: 144,
  				mass: 143.91882
  			},
  			{
  				nominal: 145,
  				mass: 144.9162726
  			},
  			{
  				nominal: 146,
  				mass: 145.917211
  			},
  			{
  				nominal: 147,
  				mass: 146.9167527
  			},
  			{
  				nominal: 148,
  				mass: 147.918089
  			},
  			{
  				nominal: 149,
  				mass: 148.9179378
  			},
  			{
  				nominal: 150,
  				mass: 149.9197077
  			},
  			{
  				nominal: 151,
  				mass: 150.9198578,
  				abundance: 0.4781
  			},
  			{
  				nominal: 152,
  				mass: 151.9217522
  			},
  			{
  				nominal: 153,
  				mass: 152.921238,
  				abundance: 0.5219
  			},
  			{
  				nominal: 154,
  				mass: 153.922987
  			},
  			{
  				nominal: 155,
  				mass: 154.9229011
  			},
  			{
  				nominal: 156,
  				mass: 155.9247605
  			},
  			{
  				nominal: 157,
  				mass: 156.9254334
  			},
  			{
  				nominal: 158,
  				mass: 157.927799
  			},
  			{
  				nominal: 159,
  				mass: 158.9291001
  			},
  			{
  				nominal: 160,
  				mass: 159.931851
  			},
  			{
  				nominal: 161,
  				mass: 160.933664
  			},
  			{
  				nominal: 162,
  				mass: 161.936989
  			},
  			{
  				nominal: 163,
  				mass: 162.939196
  			},
  			{
  				nominal: 164,
  				mass: 163.94274
  			},
  			{
  				nominal: 165,
  				mass: 164.94559
  			},
  			{
  				nominal: 166,
  				mass: 165.94962
  			},
  			{
  				nominal: 167,
  				mass: 166.95289
  			}
  		],
  		symbol: "Eu",
  		mass: 151.96437812637998,
  		name: "Europium",
  		monoisotopicMass: 152.921238
  	},
  	{
  		number: 64,
  		isotopes: [
  			{
  				nominal: 133,
  				mass: 132.96133
  			},
  			{
  				nominal: 134,
  				mass: 133.95566
  			},
  			{
  				nominal: 135,
  				mass: 134.95245
  			},
  			{
  				nominal: 136,
  				mass: 135.9473
  			},
  			{
  				nominal: 137,
  				mass: 136.94502
  			},
  			{
  				nominal: 138,
  				mass: 137.94025
  			},
  			{
  				nominal: 139,
  				mass: 138.93813
  			},
  			{
  				nominal: 140,
  				mass: 139.933674
  			},
  			{
  				nominal: 141,
  				mass: 140.932126
  			},
  			{
  				nominal: 142,
  				mass: 141.928116
  			},
  			{
  				nominal: 143,
  				mass: 142.92675
  			},
  			{
  				nominal: 144,
  				mass: 143.922963
  			},
  			{
  				nominal: 145,
  				mass: 144.921713
  			},
  			{
  				nominal: 146,
  				mass: 145.9183188
  			},
  			{
  				nominal: 147,
  				mass: 146.9191014
  			},
  			{
  				nominal: 148,
  				mass: 147.9181215
  			},
  			{
  				nominal: 149,
  				mass: 148.9193481
  			},
  			{
  				nominal: 150,
  				mass: 149.9186644
  			},
  			{
  				nominal: 151,
  				mass: 150.920356
  			},
  			{
  				nominal: 152,
  				mass: 151.9197995,
  				abundance: 0.002
  			},
  			{
  				nominal: 153,
  				mass: 152.921758
  			},
  			{
  				nominal: 154,
  				mass: 153.9208741,
  				abundance: 0.0218
  			},
  			{
  				nominal: 155,
  				mass: 154.9226305,
  				abundance: 0.148
  			},
  			{
  				nominal: 156,
  				mass: 155.9221312,
  				abundance: 0.2047
  			},
  			{
  				nominal: 157,
  				mass: 156.9239686,
  				abundance: 0.1565
  			},
  			{
  				nominal: 158,
  				mass: 157.9241123,
  				abundance: 0.2484
  			},
  			{
  				nominal: 159,
  				mass: 158.926397
  			},
  			{
  				nominal: 160,
  				mass: 159.9270624,
  				abundance: 0.2186
  			},
  			{
  				nominal: 161,
  				mass: 160.9296775
  			},
  			{
  				nominal: 162,
  				mass: 161.930993
  			},
  			{
  				nominal: 163,
  				mass: 162.9341769
  			},
  			{
  				nominal: 164,
  				mass: 163.93583
  			},
  			{
  				nominal: 165,
  				mass: 164.93936
  			},
  			{
  				nominal: 166,
  				mass: 165.94146
  			},
  			{
  				nominal: 167,
  				mass: 166.94545
  			},
  			{
  				nominal: 168,
  				mass: 167.94808
  			},
  			{
  				nominal: 169,
  				mass: 168.9526
  			}
  		],
  		symbol: "Gd",
  		mass: 157.25213064687998,
  		name: "Gadolinium",
  		monoisotopicMass: 157.9241123
  	},
  	{
  		number: 65,
  		isotopes: [
  			{
  				nominal: 135,
  				mass: 134.96476
  			},
  			{
  				nominal: 136,
  				mass: 135.96129
  			},
  			{
  				nominal: 137,
  				mass: 136.95602
  			},
  			{
  				nominal: 138,
  				mass: 137.95312
  			},
  			{
  				nominal: 139,
  				mass: 138.94833
  			},
  			{
  				nominal: 140,
  				mass: 139.94581
  			},
  			{
  				nominal: 141,
  				mass: 140.94145
  			},
  			{
  				nominal: 142,
  				mass: 141.93928
  			},
  			{
  				nominal: 143,
  				mass: 142.935137
  			},
  			{
  				nominal: 144,
  				mass: 143.933045
  			},
  			{
  				nominal: 145,
  				mass: 144.92882
  			},
  			{
  				nominal: 146,
  				mass: 145.927253
  			},
  			{
  				nominal: 147,
  				mass: 146.9240548
  			},
  			{
  				nominal: 148,
  				mass: 147.924282
  			},
  			{
  				nominal: 149,
  				mass: 148.9232535
  			},
  			{
  				nominal: 150,
  				mass: 149.9236649
  			},
  			{
  				nominal: 151,
  				mass: 150.9231096
  			},
  			{
  				nominal: 152,
  				mass: 151.924083
  			},
  			{
  				nominal: 153,
  				mass: 152.9234424
  			},
  			{
  				nominal: 154,
  				mass: 153.924685
  			},
  			{
  				nominal: 155,
  				mass: 154.923511
  			},
  			{
  				nominal: 156,
  				mass: 155.9247552
  			},
  			{
  				nominal: 157,
  				mass: 156.924033
  			},
  			{
  				nominal: 158,
  				mass: 157.9254209
  			},
  			{
  				nominal: 159,
  				mass: 158.9253547,
  				abundance: 1
  			},
  			{
  				nominal: 160,
  				mass: 159.9271756
  			},
  			{
  				nominal: 161,
  				mass: 160.9275778
  			},
  			{
  				nominal: 162,
  				mass: 161.929495
  			},
  			{
  				nominal: 163,
  				mass: 162.9306547
  			},
  			{
  				nominal: 164,
  				mass: 163.93336
  			},
  			{
  				nominal: 165,
  				mass: 164.93498
  			},
  			{
  				nominal: 166,
  				mass: 165.93786
  			},
  			{
  				nominal: 167,
  				mass: 166.93996
  			},
  			{
  				nominal: 168,
  				mass: 167.9434
  			},
  			{
  				nominal: 169,
  				mass: 168.94597
  			},
  			{
  				nominal: 170,
  				mass: 169.94984
  			},
  			{
  				nominal: 171,
  				mass: 170.95273
  			}
  		],
  		symbol: "Tb",
  		mass: 158.9253547,
  		name: "Terbium",
  		monoisotopicMass: 158.9253547
  	},
  	{
  		number: 66,
  		isotopes: [
  			{
  				nominal: 138,
  				mass: 137.9625
  			},
  			{
  				nominal: 139,
  				mass: 138.95959
  			},
  			{
  				nominal: 140,
  				mass: 139.95402
  			},
  			{
  				nominal: 141,
  				mass: 140.95128
  			},
  			{
  				nominal: 142,
  				mass: 141.94619
  			},
  			{
  				nominal: 143,
  				mass: 142.943994
  			},
  			{
  				nominal: 144,
  				mass: 143.9392695
  			},
  			{
  				nominal: 145,
  				mass: 144.937474
  			},
  			{
  				nominal: 146,
  				mass: 145.9328445
  			},
  			{
  				nominal: 147,
  				mass: 146.9310827
  			},
  			{
  				nominal: 148,
  				mass: 147.927157
  			},
  			{
  				nominal: 149,
  				mass: 148.927322
  			},
  			{
  				nominal: 150,
  				mass: 149.9255933
  			},
  			{
  				nominal: 151,
  				mass: 150.9261916
  			},
  			{
  				nominal: 152,
  				mass: 151.9247253
  			},
  			{
  				nominal: 153,
  				mass: 152.9257724
  			},
  			{
  				nominal: 154,
  				mass: 153.9244293
  			},
  			{
  				nominal: 155,
  				mass: 154.925759
  			},
  			{
  				nominal: 156,
  				mass: 155.9242847,
  				abundance: 0.00056
  			},
  			{
  				nominal: 157,
  				mass: 156.9254707
  			},
  			{
  				nominal: 158,
  				mass: 157.9244159,
  				abundance: 0.00095
  			},
  			{
  				nominal: 159,
  				mass: 158.925747
  			},
  			{
  				nominal: 160,
  				mass: 159.9252046,
  				abundance: 0.02329
  			},
  			{
  				nominal: 161,
  				mass: 160.9269405,
  				abundance: 0.18889
  			},
  			{
  				nominal: 162,
  				mass: 161.9268056,
  				abundance: 0.25475
  			},
  			{
  				nominal: 163,
  				mass: 162.9287383,
  				abundance: 0.24896
  			},
  			{
  				nominal: 164,
  				mass: 163.9291819,
  				abundance: 0.2826
  			},
  			{
  				nominal: 165,
  				mass: 164.9317105
  			},
  			{
  				nominal: 166,
  				mass: 165.9328139
  			},
  			{
  				nominal: 167,
  				mass: 166.935661
  			},
  			{
  				nominal: 168,
  				mass: 167.93713
  			},
  			{
  				nominal: 169,
  				mass: 168.94031
  			},
  			{
  				nominal: 170,
  				mass: 169.94239
  			},
  			{
  				nominal: 171,
  				mass: 170.94612
  			},
  			{
  				nominal: 172,
  				mass: 171.94846
  			},
  			{
  				nominal: 173,
  				mass: 172.95283
  			}
  		],
  		symbol: "Dy",
  		mass: 162.499472819424,
  		name: "Dysprosium",
  		monoisotopicMass: 163.9291819
  	},
  	{
  		number: 67,
  		isotopes: [
  			{
  				nominal: 140,
  				mass: 139.96859
  			},
  			{
  				nominal: 141,
  				mass: 140.96311
  			},
  			{
  				nominal: 142,
  				mass: 141.96001
  			},
  			{
  				nominal: 143,
  				mass: 142.95486
  			},
  			{
  				nominal: 144,
  				mass: 143.9521097
  			},
  			{
  				nominal: 145,
  				mass: 144.9472674
  			},
  			{
  				nominal: 146,
  				mass: 145.9449935
  			},
  			{
  				nominal: 147,
  				mass: 146.9401423
  			},
  			{
  				nominal: 148,
  				mass: 147.937744
  			},
  			{
  				nominal: 149,
  				mass: 148.933803
  			},
  			{
  				nominal: 150,
  				mass: 149.933498
  			},
  			{
  				nominal: 151,
  				mass: 150.9316983
  			},
  			{
  				nominal: 152,
  				mass: 151.931724
  			},
  			{
  				nominal: 153,
  				mass: 152.9302064
  			},
  			{
  				nominal: 154,
  				mass: 153.9306068
  			},
  			{
  				nominal: 155,
  				mass: 154.929104
  			},
  			{
  				nominal: 156,
  				mass: 155.929706
  			},
  			{
  				nominal: 157,
  				mass: 156.928254
  			},
  			{
  				nominal: 158,
  				mass: 157.928946
  			},
  			{
  				nominal: 159,
  				mass: 158.9277197
  			},
  			{
  				nominal: 160,
  				mass: 159.928737
  			},
  			{
  				nominal: 161,
  				mass: 160.9278615
  			},
  			{
  				nominal: 162,
  				mass: 161.9291023
  			},
  			{
  				nominal: 163,
  				mass: 162.928741
  			},
  			{
  				nominal: 164,
  				mass: 163.9302403
  			},
  			{
  				nominal: 165,
  				mass: 164.9303288,
  				abundance: 1
  			},
  			{
  				nominal: 166,
  				mass: 165.9322909
  			},
  			{
  				nominal: 167,
  				mass: 166.9331385
  			},
  			{
  				nominal: 168,
  				mass: 167.935522
  			},
  			{
  				nominal: 169,
  				mass: 168.936878
  			},
  			{
  				nominal: 170,
  				mass: 169.939625
  			},
  			{
  				nominal: 171,
  				mass: 170.94147
  			},
  			{
  				nominal: 172,
  				mass: 171.94473
  			},
  			{
  				nominal: 173,
  				mass: 172.94702
  			},
  			{
  				nominal: 174,
  				mass: 173.95095
  			},
  			{
  				nominal: 175,
  				mass: 174.95362
  			}
  		],
  		symbol: "Ho",
  		mass: 164.9303288,
  		name: "Holmium",
  		monoisotopicMass: 164.9303288
  	},
  	{
  		number: 68,
  		isotopes: [
  			{
  				nominal: 142,
  				mass: 141.9701
  			},
  			{
  				nominal: 143,
  				mass: 142.96662
  			},
  			{
  				nominal: 144,
  				mass: 143.9607
  			},
  			{
  				nominal: 145,
  				mass: 144.95805
  			},
  			{
  				nominal: 146,
  				mass: 145.9524184
  			},
  			{
  				nominal: 147,
  				mass: 146.949964
  			},
  			{
  				nominal: 148,
  				mass: 147.944735
  			},
  			{
  				nominal: 149,
  				mass: 148.942306
  			},
  			{
  				nominal: 150,
  				mass: 149.937916
  			},
  			{
  				nominal: 151,
  				mass: 150.937449
  			},
  			{
  				nominal: 152,
  				mass: 151.935057
  			},
  			{
  				nominal: 153,
  				mass: 152.93508
  			},
  			{
  				nominal: 154,
  				mass: 153.9327908
  			},
  			{
  				nominal: 155,
  				mass: 154.9332159
  			},
  			{
  				nominal: 156,
  				mass: 155.931067
  			},
  			{
  				nominal: 157,
  				mass: 156.931949
  			},
  			{
  				nominal: 158,
  				mass: 157.929893
  			},
  			{
  				nominal: 159,
  				mass: 158.9306918
  			},
  			{
  				nominal: 160,
  				mass: 159.929077
  			},
  			{
  				nominal: 161,
  				mass: 160.9300046
  			},
  			{
  				nominal: 162,
  				mass: 161.9287884,
  				abundance: 0.00139
  			},
  			{
  				nominal: 163,
  				mass: 162.9300408
  			},
  			{
  				nominal: 164,
  				mass: 163.9292088,
  				abundance: 0.01601
  			},
  			{
  				nominal: 165,
  				mass: 164.9307345
  			},
  			{
  				nominal: 166,
  				mass: 165.9302995,
  				abundance: 0.33503
  			},
  			{
  				nominal: 167,
  				mass: 166.9320546,
  				abundance: 0.22869
  			},
  			{
  				nominal: 168,
  				mass: 167.9323767,
  				abundance: 0.26978
  			},
  			{
  				nominal: 169,
  				mass: 168.9345968
  			},
  			{
  				nominal: 170,
  				mass: 169.9354702,
  				abundance: 0.1491
  			},
  			{
  				nominal: 171,
  				mass: 170.9380357
  			},
  			{
  				nominal: 172,
  				mass: 171.9393619
  			},
  			{
  				nominal: 173,
  				mass: 172.9424
  			},
  			{
  				nominal: 174,
  				mass: 173.94423
  			},
  			{
  				nominal: 175,
  				mass: 174.94777
  			},
  			{
  				nominal: 176,
  				mass: 175.94994
  			},
  			{
  				nominal: 177,
  				mass: 176.95399
  			}
  		],
  		symbol: "Er",
  		mass: 167.259082649669,
  		name: "Erbium",
  		monoisotopicMass: 165.9302995
  	},
  	{
  		number: 69,
  		isotopes: [
  			{
  				nominal: 144,
  				mass: 143.97628
  			},
  			{
  				nominal: 145,
  				mass: 144.97039
  			},
  			{
  				nominal: 146,
  				mass: 145.96684
  			},
  			{
  				nominal: 147,
  				mass: 146.9613799
  			},
  			{
  				nominal: 148,
  				mass: 147.958384
  			},
  			{
  				nominal: 149,
  				mass: 148.95289
  			},
  			{
  				nominal: 150,
  				mass: 149.95009
  			},
  			{
  				nominal: 151,
  				mass: 150.945488
  			},
  			{
  				nominal: 152,
  				mass: 151.944422
  			},
  			{
  				nominal: 153,
  				mass: 152.94204
  			},
  			{
  				nominal: 154,
  				mass: 153.94157
  			},
  			{
  				nominal: 155,
  				mass: 154.93921
  			},
  			{
  				nominal: 156,
  				mass: 155.938992
  			},
  			{
  				nominal: 157,
  				mass: 156.936944
  			},
  			{
  				nominal: 158,
  				mass: 157.93698
  			},
  			{
  				nominal: 159,
  				mass: 158.934975
  			},
  			{
  				nominal: 160,
  				mass: 159.935263
  			},
  			{
  				nominal: 161,
  				mass: 160.933549
  			},
  			{
  				nominal: 162,
  				mass: 161.934002
  			},
  			{
  				nominal: 163,
  				mass: 162.9326592
  			},
  			{
  				nominal: 164,
  				mass: 163.933544
  			},
  			{
  				nominal: 165,
  				mass: 164.9324431
  			},
  			{
  				nominal: 166,
  				mass: 165.933561
  			},
  			{
  				nominal: 167,
  				mass: 166.9328562
  			},
  			{
  				nominal: 168,
  				mass: 167.9341774
  			},
  			{
  				nominal: 169,
  				mass: 168.9342179,
  				abundance: 1
  			},
  			{
  				nominal: 170,
  				mass: 169.935806
  			},
  			{
  				nominal: 171,
  				mass: 170.9364339
  			},
  			{
  				nominal: 172,
  				mass: 171.9384055
  			},
  			{
  				nominal: 173,
  				mass: 172.9396084
  			},
  			{
  				nominal: 174,
  				mass: 173.942173
  			},
  			{
  				nominal: 175,
  				mass: 174.943841
  			},
  			{
  				nominal: 176,
  				mass: 175.947
  			},
  			{
  				nominal: 177,
  				mass: 176.94904
  			},
  			{
  				nominal: 178,
  				mass: 177.95264
  			},
  			{
  				nominal: 179,
  				mass: 178.95534
  			}
  		],
  		symbol: "Tm",
  		mass: 168.9342179,
  		name: "Thulium",
  		monoisotopicMass: 168.9342179
  	},
  	{
  		number: 70,
  		isotopes: [
  			{
  				nominal: 148,
  				mass: 147.96758
  			},
  			{
  				nominal: 149,
  				mass: 148.96436
  			},
  			{
  				nominal: 150,
  				mass: 149.95852
  			},
  			{
  				nominal: 151,
  				mass: 150.9554
  			},
  			{
  				nominal: 152,
  				mass: 151.95027
  			},
  			{
  				nominal: 153,
  				mass: 152.94932
  			},
  			{
  				nominal: 154,
  				mass: 153.946396
  			},
  			{
  				nominal: 155,
  				mass: 154.945783
  			},
  			{
  				nominal: 156,
  				mass: 155.942825
  			},
  			{
  				nominal: 157,
  				mass: 156.942645
  			},
  			{
  				nominal: 158,
  				mass: 157.9398705
  			},
  			{
  				nominal: 159,
  				mass: 158.940055
  			},
  			{
  				nominal: 160,
  				mass: 159.937557
  			},
  			{
  				nominal: 161,
  				mass: 160.937907
  			},
  			{
  				nominal: 162,
  				mass: 161.935774
  			},
  			{
  				nominal: 163,
  				mass: 162.93634
  			},
  			{
  				nominal: 164,
  				mass: 163.934495
  			},
  			{
  				nominal: 165,
  				mass: 164.93527
  			},
  			{
  				nominal: 166,
  				mass: 165.9338747
  			},
  			{
  				nominal: 167,
  				mass: 166.934953
  			},
  			{
  				nominal: 168,
  				mass: 167.9338896,
  				abundance: 0.00123
  			},
  			{
  				nominal: 169,
  				mass: 168.9351825
  			},
  			{
  				nominal: 170,
  				mass: 169.9347664,
  				abundance: 0.02982
  			},
  			{
  				nominal: 171,
  				mass: 170.9363302,
  				abundance: 0.1409
  			},
  			{
  				nominal: 172,
  				mass: 171.9363859,
  				abundance: 0.2168
  			},
  			{
  				nominal: 173,
  				mass: 172.9382151,
  				abundance: 0.16103
  			},
  			{
  				nominal: 174,
  				mass: 173.9388664,
  				abundance: 0.32026
  			},
  			{
  				nominal: 175,
  				mass: 174.9412808
  			},
  			{
  				nominal: 176,
  				mass: 175.9425764,
  				abundance: 0.12996
  			},
  			{
  				nominal: 177,
  				mass: 176.9452656
  			},
  			{
  				nominal: 178,
  				mass: 177.946651
  			},
  			{
  				nominal: 179,
  				mass: 178.95004
  			},
  			{
  				nominal: 180,
  				mass: 179.95212
  			},
  			{
  				nominal: 181,
  				mass: 180.95589
  			}
  		],
  		symbol: "Yb",
  		mass: 173.05415016631702,
  		name: "Ytterbium",
  		monoisotopicMass: 173.9388664
  	},
  	{
  		number: 71,
  		isotopes: [
  			{
  				nominal: 150,
  				mass: 149.97355
  			},
  			{
  				nominal: 151,
  				mass: 150.96768
  			},
  			{
  				nominal: 152,
  				mass: 151.96412
  			},
  			{
  				nominal: 153,
  				mass: 152.95875
  			},
  			{
  				nominal: 154,
  				mass: 153.95736
  			},
  			{
  				nominal: 155,
  				mass: 154.954321
  			},
  			{
  				nominal: 156,
  				mass: 155.953033
  			},
  			{
  				nominal: 157,
  				mass: 156.950127
  			},
  			{
  				nominal: 158,
  				mass: 157.949316
  			},
  			{
  				nominal: 159,
  				mass: 158.946636
  			},
  			{
  				nominal: 160,
  				mass: 159.946033
  			},
  			{
  				nominal: 161,
  				mass: 160.943572
  			},
  			{
  				nominal: 162,
  				mass: 161.943283
  			},
  			{
  				nominal: 163,
  				mass: 162.941179
  			},
  			{
  				nominal: 164,
  				mass: 163.941339
  			},
  			{
  				nominal: 165,
  				mass: 164.939407
  			},
  			{
  				nominal: 166,
  				mass: 165.939859
  			},
  			{
  				nominal: 167,
  				mass: 166.93827
  			},
  			{
  				nominal: 168,
  				mass: 167.938736
  			},
  			{
  				nominal: 169,
  				mass: 168.9376441
  			},
  			{
  				nominal: 170,
  				mass: 169.938478
  			},
  			{
  				nominal: 171,
  				mass: 170.937917
  			},
  			{
  				nominal: 172,
  				mass: 171.9390891
  			},
  			{
  				nominal: 173,
  				mass: 172.938934
  			},
  			{
  				nominal: 174,
  				mass: 173.9403409
  			},
  			{
  				nominal: 175,
  				mass: 174.9407752,
  				abundance: 0.97401
  			},
  			{
  				nominal: 176,
  				mass: 175.9426897,
  				abundance: 0.02599
  			},
  			{
  				nominal: 177,
  				mass: 176.9437615
  			},
  			{
  				nominal: 178,
  				mass: 177.945958
  			},
  			{
  				nominal: 179,
  				mass: 178.9473309
  			},
  			{
  				nominal: 180,
  				mass: 179.949888
  			},
  			{
  				nominal: 181,
  				mass: 180.95191
  			},
  			{
  				nominal: 182,
  				mass: 181.95504
  			},
  			{
  				nominal: 183,
  				mass: 182.957363
  			},
  			{
  				nominal: 184,
  				mass: 183.96091
  			},
  			{
  				nominal: 185,
  				mass: 184.96362
  			}
  		],
  		symbol: "Lu",
  		mass: 174.96681495785498,
  		name: "Lutetium",
  		monoisotopicMass: 174.9407752
  	},
  	{
  		number: 72,
  		isotopes: [
  			{
  				nominal: 153,
  				mass: 152.97069
  			},
  			{
  				nominal: 154,
  				mass: 153.96486
  			},
  			{
  				nominal: 155,
  				mass: 154.96311
  			},
  			{
  				nominal: 156,
  				mass: 155.95935
  			},
  			{
  				nominal: 157,
  				mass: 156.95824
  			},
  			{
  				nominal: 158,
  				mass: 157.954801
  			},
  			{
  				nominal: 159,
  				mass: 158.953996
  			},
  			{
  				nominal: 160,
  				mass: 159.950691
  			},
  			{
  				nominal: 161,
  				mass: 160.950278
  			},
  			{
  				nominal: 162,
  				mass: 161.9472148
  			},
  			{
  				nominal: 163,
  				mass: 162.947113
  			},
  			{
  				nominal: 164,
  				mass: 163.944371
  			},
  			{
  				nominal: 165,
  				mass: 164.944567
  			},
  			{
  				nominal: 166,
  				mass: 165.94218
  			},
  			{
  				nominal: 167,
  				mass: 166.9426
  			},
  			{
  				nominal: 168,
  				mass: 167.940568
  			},
  			{
  				nominal: 169,
  				mass: 168.941259
  			},
  			{
  				nominal: 170,
  				mass: 169.939609
  			},
  			{
  				nominal: 171,
  				mass: 170.940492
  			},
  			{
  				nominal: 172,
  				mass: 171.93945
  			},
  			{
  				nominal: 173,
  				mass: 172.940513
  			},
  			{
  				nominal: 174,
  				mass: 173.9400461,
  				abundance: 0.0016
  			},
  			{
  				nominal: 175,
  				mass: 174.9415092
  			},
  			{
  				nominal: 176,
  				mass: 175.9414076,
  				abundance: 0.0526
  			},
  			{
  				nominal: 177,
  				mass: 176.9432277,
  				abundance: 0.186
  			},
  			{
  				nominal: 178,
  				mass: 177.9437058,
  				abundance: 0.2728
  			},
  			{
  				nominal: 179,
  				mass: 178.9458232,
  				abundance: 0.1362
  			},
  			{
  				nominal: 180,
  				mass: 179.946557,
  				abundance: 0.3508
  			},
  			{
  				nominal: 181,
  				mass: 180.9491083
  			},
  			{
  				nominal: 182,
  				mass: 181.9505612
  			},
  			{
  				nominal: 183,
  				mass: 182.95353
  			},
  			{
  				nominal: 184,
  				mass: 183.955446
  			},
  			{
  				nominal: 185,
  				mass: 184.958862
  			},
  			{
  				nominal: 186,
  				mass: 185.960897
  			},
  			{
  				nominal: 187,
  				mass: 186.96477
  			},
  			{
  				nominal: 188,
  				mass: 187.96685
  			},
  			{
  				nominal: 189,
  				mass: 188.97084
  			}
  		],
  		symbol: "Hf",
  		mass: 178.4849787234,
  		name: "Hafnium",
  		monoisotopicMass: 179.946557
  	},
  	{
  		number: 73,
  		isotopes: [
  			{
  				nominal: 155,
  				mass: 154.97424
  			},
  			{
  				nominal: 156,
  				mass: 155.97203
  			},
  			{
  				nominal: 157,
  				mass: 156.96818
  			},
  			{
  				nominal: 158,
  				mass: 157.96654
  			},
  			{
  				nominal: 159,
  				mass: 158.963023
  			},
  			{
  				nominal: 160,
  				mass: 159.961488
  			},
  			{
  				nominal: 161,
  				mass: 160.958452
  			},
  			{
  				nominal: 162,
  				mass: 161.957294
  			},
  			{
  				nominal: 163,
  				mass: 162.954337
  			},
  			{
  				nominal: 164,
  				mass: 163.953534
  			},
  			{
  				nominal: 165,
  				mass: 164.950781
  			},
  			{
  				nominal: 166,
  				mass: 165.950512
  			},
  			{
  				nominal: 167,
  				mass: 166.948093
  			},
  			{
  				nominal: 168,
  				mass: 167.948047
  			},
  			{
  				nominal: 169,
  				mass: 168.946011
  			},
  			{
  				nominal: 170,
  				mass: 169.946175
  			},
  			{
  				nominal: 171,
  				mass: 170.944476
  			},
  			{
  				nominal: 172,
  				mass: 171.944895
  			},
  			{
  				nominal: 173,
  				mass: 172.94375
  			},
  			{
  				nominal: 174,
  				mass: 173.944454
  			},
  			{
  				nominal: 175,
  				mass: 174.943737
  			},
  			{
  				nominal: 176,
  				mass: 175.944857
  			},
  			{
  				nominal: 177,
  				mass: 176.9444795
  			},
  			{
  				nominal: 178,
  				mass: 177.945678
  			},
  			{
  				nominal: 179,
  				mass: 178.9459366
  			},
  			{
  				nominal: 180,
  				mass: 179.9474648,
  				abundance: 0.0001201
  			},
  			{
  				nominal: 181,
  				mass: 180.9479958,
  				abundance: 0.9998799
  			},
  			{
  				nominal: 182,
  				mass: 181.9501519
  			},
  			{
  				nominal: 183,
  				mass: 182.9513726
  			},
  			{
  				nominal: 184,
  				mass: 183.954008
  			},
  			{
  				nominal: 185,
  				mass: 184.955559
  			},
  			{
  				nominal: 186,
  				mass: 185.958551
  			},
  			{
  				nominal: 187,
  				mass: 186.960386
  			},
  			{
  				nominal: 188,
  				mass: 187.963916
  			},
  			{
  				nominal: 189,
  				mass: 188.96583
  			},
  			{
  				nominal: 190,
  				mass: 189.96939
  			},
  			{
  				nominal: 191,
  				mass: 190.97156
  			},
  			{
  				nominal: 192,
  				mass: 191.97514
  			}
  		],
  		symbol: "Ta",
  		mass: 180.9478756362269,
  		name: "Tantalum",
  		monoisotopicMass: 180.9479958
  	},
  	{
  		number: 74,
  		isotopes: [
  			{
  				nominal: 157,
  				mass: 156.97884
  			},
  			{
  				nominal: 158,
  				mass: 157.97456
  			},
  			{
  				nominal: 159,
  				mass: 158.97264
  			},
  			{
  				nominal: 160,
  				mass: 159.96846
  			},
  			{
  				nominal: 161,
  				mass: 160.9672
  			},
  			{
  				nominal: 162,
  				mass: 161.963499
  			},
  			{
  				nominal: 163,
  				mass: 162.962524
  			},
  			{
  				nominal: 164,
  				mass: 163.958961
  			},
  			{
  				nominal: 165,
  				mass: 164.958281
  			},
  			{
  				nominal: 166,
  				mass: 165.955031
  			},
  			{
  				nominal: 167,
  				mass: 166.954805
  			},
  			{
  				nominal: 168,
  				mass: 167.951806
  			},
  			{
  				nominal: 169,
  				mass: 168.951779
  			},
  			{
  				nominal: 170,
  				mass: 169.949232
  			},
  			{
  				nominal: 171,
  				mass: 170.949451
  			},
  			{
  				nominal: 172,
  				mass: 171.947292
  			},
  			{
  				nominal: 173,
  				mass: 172.947689
  			},
  			{
  				nominal: 174,
  				mass: 173.946079
  			},
  			{
  				nominal: 175,
  				mass: 174.946717
  			},
  			{
  				nominal: 176,
  				mass: 175.945634
  			},
  			{
  				nominal: 177,
  				mass: 176.946643
  			},
  			{
  				nominal: 178,
  				mass: 177.945883
  			},
  			{
  				nominal: 179,
  				mass: 178.947077
  			},
  			{
  				nominal: 180,
  				mass: 179.9467108,
  				abundance: 0.0012
  			},
  			{
  				nominal: 181,
  				mass: 180.9481978
  			},
  			{
  				nominal: 182,
  				mass: 181.94820394,
  				abundance: 0.265
  			},
  			{
  				nominal: 183,
  				mass: 182.95022275,
  				abundance: 0.1431
  			},
  			{
  				nominal: 184,
  				mass: 183.95093092,
  				abundance: 0.3064
  			},
  			{
  				nominal: 185,
  				mass: 184.95341897
  			},
  			{
  				nominal: 186,
  				mass: 185.9543628,
  				abundance: 0.2843
  			},
  			{
  				nominal: 187,
  				mass: 186.9571588
  			},
  			{
  				nominal: 188,
  				mass: 187.9584862
  			},
  			{
  				nominal: 189,
  				mass: 188.961763
  			},
  			{
  				nominal: 190,
  				mass: 189.963091
  			},
  			{
  				nominal: 191,
  				mass: 190.966531
  			},
  			{
  				nominal: 192,
  				mass: 191.96817
  			},
  			{
  				nominal: 193,
  				mass: 192.97178
  			},
  			{
  				nominal: 194,
  				mass: 193.97367
  			}
  		],
  		symbol: "W",
  		mass: 183.841777550513,
  		name: "Tungsten",
  		monoisotopicMass: 183.95093092
  	},
  	{
  		number: 75,
  		isotopes: [
  			{
  				nominal: 159,
  				mass: 158.98418
  			},
  			{
  				nominal: 160,
  				mass: 159.98182
  			},
  			{
  				nominal: 161,
  				mass: 160.97757
  			},
  			{
  				nominal: 162,
  				mass: 161.97584
  			},
  			{
  				nominal: 163,
  				mass: 162.97208
  			},
  			{
  				nominal: 164,
  				mass: 163.970453
  			},
  			{
  				nominal: 165,
  				mass: 164.967103
  			},
  			{
  				nominal: 166,
  				mass: 165.965761
  			},
  			{
  				nominal: 167,
  				mass: 166.962595
  			},
  			{
  				nominal: 168,
  				mass: 167.961573
  			},
  			{
  				nominal: 169,
  				mass: 168.958766
  			},
  			{
  				nominal: 170,
  				mass: 169.95822
  			},
  			{
  				nominal: 171,
  				mass: 170.955716
  			},
  			{
  				nominal: 172,
  				mass: 171.95542
  			},
  			{
  				nominal: 173,
  				mass: 172.953243
  			},
  			{
  				nominal: 174,
  				mass: 173.953115
  			},
  			{
  				nominal: 175,
  				mass: 174.951381
  			},
  			{
  				nominal: 176,
  				mass: 175.951623
  			},
  			{
  				nominal: 177,
  				mass: 176.950328
  			},
  			{
  				nominal: 178,
  				mass: 177.950989
  			},
  			{
  				nominal: 179,
  				mass: 178.949989
  			},
  			{
  				nominal: 180,
  				mass: 179.950792
  			},
  			{
  				nominal: 181,
  				mass: 180.950058
  			},
  			{
  				nominal: 182,
  				mass: 181.95121
  			},
  			{
  				nominal: 183,
  				mass: 182.9508196
  			},
  			{
  				nominal: 184,
  				mass: 183.9525228
  			},
  			{
  				nominal: 185,
  				mass: 184.9529545,
  				abundance: 0.374
  			},
  			{
  				nominal: 186,
  				mass: 185.9549856
  			},
  			{
  				nominal: 187,
  				mass: 186.9557501,
  				abundance: 0.626
  			},
  			{
  				nominal: 188,
  				mass: 187.9581115
  			},
  			{
  				nominal: 189,
  				mass: 188.959226
  			},
  			{
  				nominal: 190,
  				mass: 189.961744
  			},
  			{
  				nominal: 191,
  				mass: 190.963122
  			},
  			{
  				nominal: 192,
  				mass: 191.966088
  			},
  			{
  				nominal: 193,
  				mass: 192.967541
  			},
  			{
  				nominal: 194,
  				mass: 193.97076
  			},
  			{
  				nominal: 195,
  				mass: 194.97254
  			},
  			{
  				nominal: 196,
  				mass: 195.9758
  			},
  			{
  				nominal: 197,
  				mass: 196.97799
  			},
  			{
  				nominal: 198,
  				mass: 197.9816
  			}
  		],
  		symbol: "Re",
  		mass: 186.20670454560002,
  		name: "Rhenium",
  		monoisotopicMass: 186.9557501
  	},
  	{
  		number: 76,
  		isotopes: [
  			{
  				nominal: 161,
  				mass: 160.98903
  			},
  			{
  				nominal: 162,
  				mass: 161.98443
  			},
  			{
  				nominal: 163,
  				mass: 162.98241
  			},
  			{
  				nominal: 164,
  				mass: 163.97802
  			},
  			{
  				nominal: 165,
  				mass: 164.9766
  			},
  			{
  				nominal: 166,
  				mass: 165.972692
  			},
  			{
  				nominal: 167,
  				mass: 166.971549
  			},
  			{
  				nominal: 168,
  				mass: 167.967808
  			},
  			{
  				nominal: 169,
  				mass: 168.967018
  			},
  			{
  				nominal: 170,
  				mass: 169.963578
  			},
  			{
  				nominal: 171,
  				mass: 170.963174
  			},
  			{
  				nominal: 172,
  				mass: 171.960017
  			},
  			{
  				nominal: 173,
  				mass: 172.959808
  			},
  			{
  				nominal: 174,
  				mass: 173.957064
  			},
  			{
  				nominal: 175,
  				mass: 174.956945
  			},
  			{
  				nominal: 176,
  				mass: 175.954806
  			},
  			{
  				nominal: 177,
  				mass: 176.954966
  			},
  			{
  				nominal: 178,
  				mass: 177.953254
  			},
  			{
  				nominal: 179,
  				mass: 178.953817
  			},
  			{
  				nominal: 180,
  				mass: 179.952375
  			},
  			{
  				nominal: 181,
  				mass: 180.953247
  			},
  			{
  				nominal: 182,
  				mass: 181.95211
  			},
  			{
  				nominal: 183,
  				mass: 182.953125
  			},
  			{
  				nominal: 184,
  				mass: 183.9524885,
  				abundance: 0.0002
  			},
  			{
  				nominal: 185,
  				mass: 184.9540417
  			},
  			{
  				nominal: 186,
  				mass: 185.953835,
  				abundance: 0.0159
  			},
  			{
  				nominal: 187,
  				mass: 186.9557474,
  				abundance: 0.0196
  			},
  			{
  				nominal: 188,
  				mass: 187.9558352,
  				abundance: 0.1324
  			},
  			{
  				nominal: 189,
  				mass: 188.9581442,
  				abundance: 0.1615
  			},
  			{
  				nominal: 190,
  				mass: 189.9584437,
  				abundance: 0.2626
  			},
  			{
  				nominal: 191,
  				mass: 190.9609264
  			},
  			{
  				nominal: 192,
  				mass: 191.961477,
  				abundance: 0.4078
  			},
  			{
  				nominal: 193,
  				mass: 192.9641479
  			},
  			{
  				nominal: 194,
  				mass: 193.9651772
  			},
  			{
  				nominal: 195,
  				mass: 194.968318
  			},
  			{
  				nominal: 196,
  				mass: 195.969641
  			},
  			{
  				nominal: 197,
  				mass: 196.97283
  			},
  			{
  				nominal: 198,
  				mass: 197.97441
  			},
  			{
  				nominal: 199,
  				mass: 198.97801
  			},
  			{
  				nominal: 200,
  				mass: 199.97984
  			},
  			{
  				nominal: 201,
  				mass: 200.98364
  			},
  			{
  				nominal: 202,
  				mass: 201.98595
  			}
  		],
  		symbol: "Os",
  		mass: 190.22485962823998,
  		name: "Osmium",
  		monoisotopicMass: 191.961477
  	},
  	{
  		number: 77,
  		isotopes: [
  			{
  				nominal: 164,
  				mass: 163.99191
  			},
  			{
  				nominal: 165,
  				mass: 164.9875
  			},
  			{
  				nominal: 166,
  				mass: 165.98566
  			},
  			{
  				nominal: 167,
  				mass: 166.981666
  			},
  			{
  				nominal: 168,
  				mass: 167.979907
  			},
  			{
  				nominal: 169,
  				mass: 168.976298
  			},
  			{
  				nominal: 170,
  				mass: 169.974922
  			},
  			{
  				nominal: 171,
  				mass: 170.97164
  			},
  			{
  				nominal: 172,
  				mass: 171.970607
  			},
  			{
  				nominal: 173,
  				mass: 172.967506
  			},
  			{
  				nominal: 174,
  				mass: 173.966861
  			},
  			{
  				nominal: 175,
  				mass: 174.96415
  			},
  			{
  				nominal: 176,
  				mass: 175.96365
  			},
  			{
  				nominal: 177,
  				mass: 176.961301
  			},
  			{
  				nominal: 178,
  				mass: 177.961082
  			},
  			{
  				nominal: 179,
  				mass: 178.95912
  			},
  			{
  				nominal: 180,
  				mass: 179.959229
  			},
  			{
  				nominal: 181,
  				mass: 180.957625
  			},
  			{
  				nominal: 182,
  				mass: 181.958076
  			},
  			{
  				nominal: 183,
  				mass: 182.95684
  			},
  			{
  				nominal: 184,
  				mass: 183.957476
  			},
  			{
  				nominal: 185,
  				mass: 184.956698
  			},
  			{
  				nominal: 186,
  				mass: 185.957944
  			},
  			{
  				nominal: 187,
  				mass: 186.957542
  			},
  			{
  				nominal: 188,
  				mass: 187.958828
  			},
  			{
  				nominal: 189,
  				mass: 188.958715
  			},
  			{
  				nominal: 190,
  				mass: 189.9605412
  			},
  			{
  				nominal: 191,
  				mass: 190.9605893,
  				abundance: 0.373
  			},
  			{
  				nominal: 192,
  				mass: 191.9626002
  			},
  			{
  				nominal: 193,
  				mass: 192.9629216,
  				abundance: 0.627
  			},
  			{
  				nominal: 194,
  				mass: 193.9650735
  			},
  			{
  				nominal: 195,
  				mass: 194.9659747
  			},
  			{
  				nominal: 196,
  				mass: 195.968397
  			},
  			{
  				nominal: 197,
  				mass: 196.969655
  			},
  			{
  				nominal: 198,
  				mass: 197.97228
  			},
  			{
  				nominal: 199,
  				mass: 198.973805
  			},
  			{
  				nominal: 200,
  				mass: 199.9768
  			},
  			{
  				nominal: 201,
  				mass: 200.97864
  			},
  			{
  				nominal: 202,
  				mass: 201.98199
  			},
  			{
  				nominal: 203,
  				mass: 202.98423
  			},
  			{
  				nominal: 204,
  				mass: 203.9896
  			}
  		],
  		symbol: "Ir",
  		mass: 192.2160516521,
  		name: "Iridium",
  		monoisotopicMass: 192.9629216
  	},
  	{
  		number: 78,
  		isotopes: [
  			{
  				nominal: 166,
  				mass: 165.99486
  			},
  			{
  				nominal: 167,
  				mass: 166.99269
  			},
  			{
  				nominal: 168,
  				mass: 167.98813
  			},
  			{
  				nominal: 169,
  				mass: 168.98657
  			},
  			{
  				nominal: 170,
  				mass: 169.982496
  			},
  			{
  				nominal: 171,
  				mass: 170.981245
  			},
  			{
  				nominal: 172,
  				mass: 171.977351
  			},
  			{
  				nominal: 173,
  				mass: 172.976443
  			},
  			{
  				nominal: 174,
  				mass: 173.97282
  			},
  			{
  				nominal: 175,
  				mass: 174.97241
  			},
  			{
  				nominal: 176,
  				mass: 175.968938
  			},
  			{
  				nominal: 177,
  				mass: 176.96847
  			},
  			{
  				nominal: 178,
  				mass: 177.96565
  			},
  			{
  				nominal: 179,
  				mass: 178.965359
  			},
  			{
  				nominal: 180,
  				mass: 179.963032
  			},
  			{
  				nominal: 181,
  				mass: 180.963098
  			},
  			{
  				nominal: 182,
  				mass: 181.961172
  			},
  			{
  				nominal: 183,
  				mass: 182.961597
  			},
  			{
  				nominal: 184,
  				mass: 183.959915
  			},
  			{
  				nominal: 185,
  				mass: 184.960614
  			},
  			{
  				nominal: 186,
  				mass: 185.959351
  			},
  			{
  				nominal: 187,
  				mass: 186.960617
  			},
  			{
  				nominal: 188,
  				mass: 187.9593889
  			},
  			{
  				nominal: 189,
  				mass: 188.960831
  			},
  			{
  				nominal: 190,
  				mass: 189.9599297,
  				abundance: 0.00012
  			},
  			{
  				nominal: 191,
  				mass: 190.9616729
  			},
  			{
  				nominal: 192,
  				mass: 191.9610387,
  				abundance: 0.00782
  			},
  			{
  				nominal: 193,
  				mass: 192.9629824
  			},
  			{
  				nominal: 194,
  				mass: 193.9626809,
  				abundance: 0.3286
  			},
  			{
  				nominal: 195,
  				mass: 194.9647917,
  				abundance: 0.3378
  			},
  			{
  				nominal: 196,
  				mass: 195.96495209,
  				abundance: 0.2521
  			},
  			{
  				nominal: 197,
  				mass: 196.96734069
  			},
  			{
  				nominal: 198,
  				mass: 197.9678949,
  				abundance: 0.07356
  			},
  			{
  				nominal: 199,
  				mass: 198.9705952
  			},
  			{
  				nominal: 200,
  				mass: 199.971443
  			},
  			{
  				nominal: 201,
  				mass: 200.974513
  			},
  			{
  				nominal: 202,
  				mass: 201.975639
  			},
  			{
  				nominal: 203,
  				mass: 202.97893
  			},
  			{
  				nominal: 204,
  				mass: 203.98076
  			},
  			{
  				nominal: 205,
  				mass: 204.98608
  			},
  			{
  				nominal: 206,
  				mass: 205.98966
  			}
  		],
  		symbol: "Pt",
  		mass: 195.084456864931,
  		name: "Platinum",
  		monoisotopicMass: 194.9647917
  	},
  	{
  		number: 79,
  		isotopes: [
  			{
  				nominal: 169,
  				mass: 168.99808
  			},
  			{
  				nominal: 170,
  				mass: 169.99597
  			},
  			{
  				nominal: 171,
  				mass: 170.991876
  			},
  			{
  				nominal: 172,
  				mass: 171.989942
  			},
  			{
  				nominal: 173,
  				mass: 172.986241
  			},
  			{
  				nominal: 174,
  				mass: 173.984717
  			},
  			{
  				nominal: 175,
  				mass: 174.981304
  			},
  			{
  				nominal: 176,
  				mass: 175.98025
  			},
  			{
  				nominal: 177,
  				mass: 176.97687
  			},
  			{
  				nominal: 178,
  				mass: 177.976032
  			},
  			{
  				nominal: 179,
  				mass: 178.973174
  			},
  			{
  				nominal: 180,
  				mass: 179.972523
  			},
  			{
  				nominal: 181,
  				mass: 180.970079
  			},
  			{
  				nominal: 182,
  				mass: 181.969618
  			},
  			{
  				nominal: 183,
  				mass: 182.967591
  			},
  			{
  				nominal: 184,
  				mass: 183.967452
  			},
  			{
  				nominal: 185,
  				mass: 184.96579
  			},
  			{
  				nominal: 186,
  				mass: 185.965953
  			},
  			{
  				nominal: 187,
  				mass: 186.964543
  			},
  			{
  				nominal: 188,
  				mass: 187.965349
  			},
  			{
  				nominal: 189,
  				mass: 188.963948
  			},
  			{
  				nominal: 190,
  				mass: 189.964698
  			},
  			{
  				nominal: 191,
  				mass: 190.963702
  			},
  			{
  				nominal: 192,
  				mass: 191.964814
  			},
  			{
  				nominal: 193,
  				mass: 192.9641373
  			},
  			{
  				nominal: 194,
  				mass: 193.9654178
  			},
  			{
  				nominal: 195,
  				mass: 194.9650352
  			},
  			{
  				nominal: 196,
  				mass: 195.9665699
  			},
  			{
  				nominal: 197,
  				mass: 196.96656879,
  				abundance: 1
  			},
  			{
  				nominal: 198,
  				mass: 197.96824242
  			},
  			{
  				nominal: 199,
  				mass: 198.96876528
  			},
  			{
  				nominal: 200,
  				mass: 199.970756
  			},
  			{
  				nominal: 201,
  				mass: 200.9716575
  			},
  			{
  				nominal: 202,
  				mass: 201.973856
  			},
  			{
  				nominal: 203,
  				mass: 202.9751544
  			},
  			{
  				nominal: 204,
  				mass: 203.97783
  			},
  			{
  				nominal: 205,
  				mass: 204.97985
  			},
  			{
  				nominal: 206,
  				mass: 205.98474
  			},
  			{
  				nominal: 207,
  				mass: 206.9884
  			},
  			{
  				nominal: 208,
  				mass: 207.99345
  			},
  			{
  				nominal: 209,
  				mass: 208.99735
  			},
  			{
  				nominal: 210,
  				mass: 210.0025
  			}
  		],
  		symbol: "Au",
  		mass: 196.96656879,
  		name: "Gold",
  		monoisotopicMass: 196.96656879
  	},
  	{
  		number: 80,
  		isotopes: [
  			{
  				nominal: 171,
  				mass: 171.00353
  			},
  			{
  				nominal: 172,
  				mass: 171.99881
  			},
  			{
  				nominal: 173,
  				mass: 172.99709
  			},
  			{
  				nominal: 174,
  				mass: 173.992865
  			},
  			{
  				nominal: 175,
  				mass: 174.991441
  			},
  			{
  				nominal: 176,
  				mass: 175.987361
  			},
  			{
  				nominal: 177,
  				mass: 176.986277
  			},
  			{
  				nominal: 178,
  				mass: 177.982484
  			},
  			{
  				nominal: 179,
  				mass: 178.981831
  			},
  			{
  				nominal: 180,
  				mass: 179.97826
  			},
  			{
  				nominal: 181,
  				mass: 180.977819
  			},
  			{
  				nominal: 182,
  				mass: 181.974689
  			},
  			{
  				nominal: 183,
  				mass: 182.9744448
  			},
  			{
  				nominal: 184,
  				mass: 183.971714
  			},
  			{
  				nominal: 185,
  				mass: 184.971899
  			},
  			{
  				nominal: 186,
  				mass: 185.969362
  			},
  			{
  				nominal: 187,
  				mass: 186.969814
  			},
  			{
  				nominal: 188,
  				mass: 187.967567
  			},
  			{
  				nominal: 189,
  				mass: 188.968195
  			},
  			{
  				nominal: 190,
  				mass: 189.966323
  			},
  			{
  				nominal: 191,
  				mass: 190.967157
  			},
  			{
  				nominal: 192,
  				mass: 191.965635
  			},
  			{
  				nominal: 193,
  				mass: 192.966653
  			},
  			{
  				nominal: 194,
  				mass: 193.9654491
  			},
  			{
  				nominal: 195,
  				mass: 194.966721
  			},
  			{
  				nominal: 196,
  				mass: 195.9658326,
  				abundance: 0.0015
  			},
  			{
  				nominal: 197,
  				mass: 196.9672128
  			},
  			{
  				nominal: 198,
  				mass: 197.9667686,
  				abundance: 0.0997
  			},
  			{
  				nominal: 199,
  				mass: 198.96828064,
  				abundance: 0.1687
  			},
  			{
  				nominal: 200,
  				mass: 199.96832659,
  				abundance: 0.231
  			},
  			{
  				nominal: 201,
  				mass: 200.97030284,
  				abundance: 0.1318
  			},
  			{
  				nominal: 202,
  				mass: 201.9706434,
  				abundance: 0.2986
  			},
  			{
  				nominal: 203,
  				mass: 202.9728728
  			},
  			{
  				nominal: 204,
  				mass: 203.97349398,
  				abundance: 0.0687
  			},
  			{
  				nominal: 205,
  				mass: 204.9760734
  			},
  			{
  				nominal: 206,
  				mass: 205.977514
  			},
  			{
  				nominal: 207,
  				mass: 206.9823
  			},
  			{
  				nominal: 208,
  				mass: 207.985759
  			},
  			{
  				nominal: 209,
  				mass: 208.99072
  			},
  			{
  				nominal: 210,
  				mass: 209.99424
  			},
  			{
  				nominal: 211,
  				mass: 210.99933
  			},
  			{
  				nominal: 212,
  				mass: 212.00296
  			},
  			{
  				nominal: 213,
  				mass: 213.00823
  			},
  			{
  				nominal: 214,
  				mass: 214.012
  			},
  			{
  				nominal: 215,
  				mass: 215.0174
  			},
  			{
  				nominal: 216,
  				mass: 216.02132
  			}
  		],
  		symbol: "Hg",
  		mass: 200.59916703455602,
  		name: "Mercury",
  		monoisotopicMass: 201.9706434
  	},
  	{
  		number: 81,
  		isotopes: [
  			{
  				nominal: 176,
  				mass: 176.000624
  			},
  			{
  				nominal: 177,
  				mass: 176.996431
  			},
  			{
  				nominal: 178,
  				mass: 177.99485
  			},
  			{
  				nominal: 179,
  				mass: 178.991111
  			},
  			{
  				nominal: 180,
  				mass: 179.990057
  			},
  			{
  				nominal: 181,
  				mass: 180.98626
  			},
  			{
  				nominal: 182,
  				mass: 181.985713
  			},
  			{
  				nominal: 183,
  				mass: 182.982193
  			},
  			{
  				nominal: 184,
  				mass: 183.981886
  			},
  			{
  				nominal: 185,
  				mass: 184.978789
  			},
  			{
  				nominal: 186,
  				mass: 185.978651
  			},
  			{
  				nominal: 187,
  				mass: 186.9759063
  			},
  			{
  				nominal: 188,
  				mass: 187.976021
  			},
  			{
  				nominal: 189,
  				mass: 188.973588
  			},
  			{
  				nominal: 190,
  				mass: 189.973828
  			},
  			{
  				nominal: 191,
  				mass: 190.9717842
  			},
  			{
  				nominal: 192,
  				mass: 191.972225
  			},
  			{
  				nominal: 193,
  				mass: 192.970502
  			},
  			{
  				nominal: 194,
  				mass: 193.971081
  			},
  			{
  				nominal: 195,
  				mass: 194.969774
  			},
  			{
  				nominal: 196,
  				mass: 195.970481
  			},
  			{
  				nominal: 197,
  				mass: 196.969576
  			},
  			{
  				nominal: 198,
  				mass: 197.970483
  			},
  			{
  				nominal: 199,
  				mass: 198.969877
  			},
  			{
  				nominal: 200,
  				mass: 199.9709633
  			},
  			{
  				nominal: 201,
  				mass: 200.970822
  			},
  			{
  				nominal: 202,
  				mass: 201.972102
  			},
  			{
  				nominal: 203,
  				mass: 202.9723446,
  				abundance: 0.2952
  			},
  			{
  				nominal: 204,
  				mass: 203.9738639
  			},
  			{
  				nominal: 205,
  				mass: 204.9744278,
  				abundance: 0.7048
  			},
  			{
  				nominal: 206,
  				mass: 205.9761106
  			},
  			{
  				nominal: 207,
  				mass: 206.9774197
  			},
  			{
  				nominal: 208,
  				mass: 207.982019
  			},
  			{
  				nominal: 209,
  				mass: 208.9853594
  			},
  			{
  				nominal: 210,
  				mass: 209.990074
  			},
  			{
  				nominal: 211,
  				mass: 210.993475
  			},
  			{
  				nominal: 212,
  				mass: 211.99834
  			},
  			{
  				nominal: 213,
  				mass: 213.001915
  			},
  			{
  				nominal: 214,
  				mass: 214.00694
  			},
  			{
  				nominal: 215,
  				mass: 215.01064
  			},
  			{
  				nominal: 216,
  				mass: 216.0158
  			},
  			{
  				nominal: 217,
  				mass: 217.01966
  			},
  			{
  				nominal: 218,
  				mass: 218.02479
  			}
  		],
  		symbol: "Tl",
  		mass: 204.38341283936,
  		name: "Thallium",
  		monoisotopicMass: 204.9744278
  	},
  	{
  		number: 82,
  		isotopes: [
  			{
  				nominal: 178,
  				mass: 178.003831
  			},
  			{
  				nominal: 179,
  				mass: 179.002201
  			},
  			{
  				nominal: 180,
  				mass: 179.997928
  			},
  			{
  				nominal: 181,
  				mass: 180.996653
  			},
  			{
  				nominal: 182,
  				mass: 181.992672
  			},
  			{
  				nominal: 183,
  				mass: 182.991872
  			},
  			{
  				nominal: 184,
  				mass: 183.988136
  			},
  			{
  				nominal: 185,
  				mass: 184.98761
  			},
  			{
  				nominal: 186,
  				mass: 185.984238
  			},
  			{
  				nominal: 187,
  				mass: 186.9839109
  			},
  			{
  				nominal: 188,
  				mass: 187.980875
  			},
  			{
  				nominal: 189,
  				mass: 188.980807
  			},
  			{
  				nominal: 190,
  				mass: 189.978082
  			},
  			{
  				nominal: 191,
  				mass: 190.978276
  			},
  			{
  				nominal: 192,
  				mass: 191.975775
  			},
  			{
  				nominal: 193,
  				mass: 192.976173
  			},
  			{
  				nominal: 194,
  				mass: 193.974012
  			},
  			{
  				nominal: 195,
  				mass: 194.974543
  			},
  			{
  				nominal: 196,
  				mass: 195.972774
  			},
  			{
  				nominal: 197,
  				mass: 196.9734312
  			},
  			{
  				nominal: 198,
  				mass: 197.972034
  			},
  			{
  				nominal: 199,
  				mass: 198.972913
  			},
  			{
  				nominal: 200,
  				mass: 199.971819
  			},
  			{
  				nominal: 201,
  				mass: 200.972883
  			},
  			{
  				nominal: 202,
  				mass: 201.972152
  			},
  			{
  				nominal: 203,
  				mass: 202.9733911
  			},
  			{
  				nominal: 204,
  				mass: 203.973044,
  				abundance: 0.014
  			},
  			{
  				nominal: 205,
  				mass: 204.9744822
  			},
  			{
  				nominal: 206,
  				mass: 205.9744657,
  				abundance: 0.241
  			},
  			{
  				nominal: 207,
  				mass: 206.9758973,
  				abundance: 0.221
  			},
  			{
  				nominal: 208,
  				mass: 207.9766525,
  				abundance: 0.524
  			},
  			{
  				nominal: 209,
  				mass: 208.9810905
  			},
  			{
  				nominal: 210,
  				mass: 209.9841889
  			},
  			{
  				nominal: 211,
  				mass: 210.9887371
  			},
  			{
  				nominal: 212,
  				mass: 211.9918977
  			},
  			{
  				nominal: 213,
  				mass: 212.9965629
  			},
  			{
  				nominal: 214,
  				mass: 213.9998059
  			},
  			{
  				nominal: 215,
  				mass: 215.00474
  			},
  			{
  				nominal: 216,
  				mass: 216.00803
  			},
  			{
  				nominal: 217,
  				mass: 217.01314
  			},
  			{
  				nominal: 218,
  				mass: 218.01659
  			},
  			{
  				nominal: 219,
  				mass: 219.02177
  			},
  			{
  				nominal: 220,
  				mass: 220.02541
  			}
  		],
  		symbol: "Pb",
  		mass: 207.216908063,
  		name: "Lead",
  		monoisotopicMass: 207.9766525
  	},
  	{
  		number: 83,
  		isotopes: [
  			{
  				nominal: 184,
  				mass: 184.001275
  			},
  			{
  				nominal: 185,
  				mass: 184.9976
  			},
  			{
  				nominal: 186,
  				mass: 185.996644
  			},
  			{
  				nominal: 187,
  				mass: 186.993147
  			},
  			{
  				nominal: 188,
  				mass: 187.992287
  			},
  			{
  				nominal: 189,
  				mass: 188.989195
  			},
  			{
  				nominal: 190,
  				mass: 189.988622
  			},
  			{
  				nominal: 191,
  				mass: 190.9857866
  			},
  			{
  				nominal: 192,
  				mass: 191.985469
  			},
  			{
  				nominal: 193,
  				mass: 192.98296
  			},
  			{
  				nominal: 194,
  				mass: 193.982785
  			},
  			{
  				nominal: 195,
  				mass: 194.9806488
  			},
  			{
  				nominal: 196,
  				mass: 195.980667
  			},
  			{
  				nominal: 197,
  				mass: 196.9788651
  			},
  			{
  				nominal: 198,
  				mass: 197.979206
  			},
  			{
  				nominal: 199,
  				mass: 198.977673
  			},
  			{
  				nominal: 200,
  				mass: 199.978131
  			},
  			{
  				nominal: 201,
  				mass: 200.97701
  			},
  			{
  				nominal: 202,
  				mass: 201.977734
  			},
  			{
  				nominal: 203,
  				mass: 202.976893
  			},
  			{
  				nominal: 204,
  				mass: 203.9778361
  			},
  			{
  				nominal: 205,
  				mass: 204.9773867
  			},
  			{
  				nominal: 206,
  				mass: 205.9784993
  			},
  			{
  				nominal: 207,
  				mass: 206.978471
  			},
  			{
  				nominal: 208,
  				mass: 207.9797425
  			},
  			{
  				nominal: 209,
  				mass: 208.9803991,
  				abundance: 1
  			},
  			{
  				nominal: 210,
  				mass: 209.9841207
  			},
  			{
  				nominal: 211,
  				mass: 210.9872697
  			},
  			{
  				nominal: 212,
  				mass: 211.991286
  			},
  			{
  				nominal: 213,
  				mass: 212.9943851
  			},
  			{
  				nominal: 214,
  				mass: 213.998712
  			},
  			{
  				nominal: 215,
  				mass: 215.00177
  			},
  			{
  				nominal: 216,
  				mass: 216.006306
  			},
  			{
  				nominal: 217,
  				mass: 217.009372
  			},
  			{
  				nominal: 218,
  				mass: 218.014188
  			},
  			{
  				nominal: 219,
  				mass: 219.01748
  			},
  			{
  				nominal: 220,
  				mass: 220.02235
  			},
  			{
  				nominal: 221,
  				mass: 221.02587
  			},
  			{
  				nominal: 222,
  				mass: 222.03078
  			},
  			{
  				nominal: 223,
  				mass: 223.0345
  			},
  			{
  				nominal: 224,
  				mass: 224.03947
  			}
  		],
  		symbol: "Bi",
  		mass: 208.9803991,
  		name: "Bismuth",
  		monoisotopicMass: 208.9803991
  	},
  	{
  		number: 84,
  		isotopes: [
  			{
  				nominal: 186,
  				mass: 186.004393
  			},
  			{
  				nominal: 187,
  				mass: 187.003041
  			},
  			{
  				nominal: 188,
  				mass: 187.999416
  			},
  			{
  				nominal: 189,
  				mass: 188.998473
  			},
  			{
  				nominal: 190,
  				mass: 189.995101
  			},
  			{
  				nominal: 191,
  				mass: 190.9945585
  			},
  			{
  				nominal: 192,
  				mass: 191.991336
  			},
  			{
  				nominal: 193,
  				mass: 192.991026
  			},
  			{
  				nominal: 194,
  				mass: 193.988186
  			},
  			{
  				nominal: 195,
  				mass: 194.988126
  			},
  			{
  				nominal: 196,
  				mass: 195.985526
  			},
  			{
  				nominal: 197,
  				mass: 196.98566
  			},
  			{
  				nominal: 198,
  				mass: 197.983389
  			},
  			{
  				nominal: 199,
  				mass: 198.983667
  			},
  			{
  				nominal: 200,
  				mass: 199.981799
  			},
  			{
  				nominal: 201,
  				mass: 200.9822598
  			},
  			{
  				nominal: 202,
  				mass: 201.980758
  			},
  			{
  				nominal: 203,
  				mass: 202.9814161
  			},
  			{
  				nominal: 204,
  				mass: 203.98031
  			},
  			{
  				nominal: 205,
  				mass: 204.981203
  			},
  			{
  				nominal: 206,
  				mass: 205.980474
  			},
  			{
  				nominal: 207,
  				mass: 206.9815938
  			},
  			{
  				nominal: 208,
  				mass: 207.9812461
  			},
  			{
  				nominal: 209,
  				mass: 208.9824308
  			},
  			{
  				nominal: 210,
  				mass: 209.9828741
  			},
  			{
  				nominal: 211,
  				mass: 210.9866536
  			},
  			{
  				nominal: 212,
  				mass: 211.9888684
  			},
  			{
  				nominal: 213,
  				mass: 212.9928576
  			},
  			{
  				nominal: 214,
  				mass: 213.9952017
  			},
  			{
  				nominal: 215,
  				mass: 214.9994201
  			},
  			{
  				nominal: 216,
  				mass: 216.0019152
  			},
  			{
  				nominal: 217,
  				mass: 217.0063182
  			},
  			{
  				nominal: 218,
  				mass: 218.0089735
  			},
  			{
  				nominal: 219,
  				mass: 219.013614
  			},
  			{
  				nominal: 220,
  				mass: 220.016386
  			},
  			{
  				nominal: 221,
  				mass: 221.021228
  			},
  			{
  				nominal: 222,
  				mass: 222.02414
  			},
  			{
  				nominal: 223,
  				mass: 223.02907
  			},
  			{
  				nominal: 224,
  				mass: 224.03211
  			},
  			{
  				nominal: 225,
  				mass: 225.03707
  			},
  			{
  				nominal: 226,
  				mass: 226.04031
  			},
  			{
  				nominal: 227,
  				mass: 227.04539
  			}
  		],
  		symbol: "Po",
  		mass: null,
  		name: "Polonium"
  	},
  	{
  		number: 85,
  		isotopes: [
  			{
  				nominal: 191,
  				mass: 191.004148
  			},
  			{
  				nominal: 192,
  				mass: 192.003152
  			},
  			{
  				nominal: 193,
  				mass: 192.999927
  			},
  			{
  				nominal: 194,
  				mass: 193.999236
  			},
  			{
  				nominal: 195,
  				mass: 194.9962685
  			},
  			{
  				nominal: 196,
  				mass: 195.9958
  			},
  			{
  				nominal: 197,
  				mass: 196.993189
  			},
  			{
  				nominal: 198,
  				mass: 197.992784
  			},
  			{
  				nominal: 199,
  				mass: 198.9905277
  			},
  			{
  				nominal: 200,
  				mass: 199.990351
  			},
  			{
  				nominal: 201,
  				mass: 200.9884171
  			},
  			{
  				nominal: 202,
  				mass: 201.98863
  			},
  			{
  				nominal: 203,
  				mass: 202.986943
  			},
  			{
  				nominal: 204,
  				mass: 203.987251
  			},
  			{
  				nominal: 205,
  				mass: 204.986076
  			},
  			{
  				nominal: 206,
  				mass: 205.986657
  			},
  			{
  				nominal: 207,
  				mass: 206.9858
  			},
  			{
  				nominal: 208,
  				mass: 207.9866133
  			},
  			{
  				nominal: 209,
  				mass: 208.9861702
  			},
  			{
  				nominal: 210,
  				mass: 209.9871479
  			},
  			{
  				nominal: 211,
  				mass: 210.9874966
  			},
  			{
  				nominal: 212,
  				mass: 211.9907377
  			},
  			{
  				nominal: 213,
  				mass: 212.992937
  			},
  			{
  				nominal: 214,
  				mass: 213.9963721
  			},
  			{
  				nominal: 215,
  				mass: 214.9986528
  			},
  			{
  				nominal: 216,
  				mass: 216.0024236
  			},
  			{
  				nominal: 217,
  				mass: 217.0047192
  			},
  			{
  				nominal: 218,
  				mass: 218.008695
  			},
  			{
  				nominal: 219,
  				mass: 219.0111618
  			},
  			{
  				nominal: 220,
  				mass: 220.015433
  			},
  			{
  				nominal: 221,
  				mass: 221.018017
  			},
  			{
  				nominal: 222,
  				mass: 222.022494
  			},
  			{
  				nominal: 223,
  				mass: 223.025151
  			},
  			{
  				nominal: 224,
  				mass: 224.029749
  			},
  			{
  				nominal: 225,
  				mass: 225.03263
  			},
  			{
  				nominal: 226,
  				mass: 226.03716
  			},
  			{
  				nominal: 227,
  				mass: 227.04024
  			},
  			{
  				nominal: 228,
  				mass: 228.04475
  			},
  			{
  				nominal: 229,
  				mass: 229.04812
  			}
  		],
  		symbol: "At",
  		mass: null,
  		name: "Astatine"
  	},
  	{
  		number: 86,
  		isotopes: [
  			{
  				nominal: 193,
  				mass: 193.009708
  			},
  			{
  				nominal: 194,
  				mass: 194.006144
  			},
  			{
  				nominal: 195,
  				mass: 195.005422
  			},
  			{
  				nominal: 196,
  				mass: 196.002116
  			},
  			{
  				nominal: 197,
  				mass: 197.001585
  			},
  			{
  				nominal: 198,
  				mass: 197.998679
  			},
  			{
  				nominal: 199,
  				mass: 198.99839
  			},
  			{
  				nominal: 200,
  				mass: 199.99569
  			},
  			{
  				nominal: 201,
  				mass: 200.995628
  			},
  			{
  				nominal: 202,
  				mass: 201.993264
  			},
  			{
  				nominal: 203,
  				mass: 202.993388
  			},
  			{
  				nominal: 204,
  				mass: 203.99143
  			},
  			{
  				nominal: 205,
  				mass: 204.991719
  			},
  			{
  				nominal: 206,
  				mass: 205.990214
  			},
  			{
  				nominal: 207,
  				mass: 206.9907303
  			},
  			{
  				nominal: 208,
  				mass: 207.989635
  			},
  			{
  				nominal: 209,
  				mass: 208.990415
  			},
  			{
  				nominal: 210,
  				mass: 209.9896891
  			},
  			{
  				nominal: 211,
  				mass: 210.9906011
  			},
  			{
  				nominal: 212,
  				mass: 211.9907039
  			},
  			{
  				nominal: 213,
  				mass: 212.9938831
  			},
  			{
  				nominal: 214,
  				mass: 213.995363
  			},
  			{
  				nominal: 215,
  				mass: 214.9987459
  			},
  			{
  				nominal: 216,
  				mass: 216.0002719
  			},
  			{
  				nominal: 217,
  				mass: 217.003928
  			},
  			{
  				nominal: 218,
  				mass: 218.0056016
  			},
  			{
  				nominal: 219,
  				mass: 219.0094804
  			},
  			{
  				nominal: 220,
  				mass: 220.0113941
  			},
  			{
  				nominal: 221,
  				mass: 221.0155371
  			},
  			{
  				nominal: 222,
  				mass: 222.0175782
  			},
  			{
  				nominal: 223,
  				mass: 223.0218893
  			},
  			{
  				nominal: 224,
  				mass: 224.024096
  			},
  			{
  				nominal: 225,
  				mass: 225.028486
  			},
  			{
  				nominal: 226,
  				mass: 226.030861
  			},
  			{
  				nominal: 227,
  				mass: 227.035304
  			},
  			{
  				nominal: 228,
  				mass: 228.037835
  			},
  			{
  				nominal: 229,
  				mass: 229.042257
  			},
  			{
  				nominal: 230,
  				mass: 230.04514
  			},
  			{
  				nominal: 231,
  				mass: 231.04987
  			}
  		],
  		symbol: "Rn",
  		mass: null,
  		name: "Radon"
  	},
  	{
  		number: 87,
  		isotopes: [
  			{
  				nominal: 199,
  				mass: 199.007259
  			},
  			{
  				nominal: 200,
  				mass: 200.006586
  			},
  			{
  				nominal: 201,
  				mass: 201.003867
  			},
  			{
  				nominal: 202,
  				mass: 202.00332
  			},
  			{
  				nominal: 203,
  				mass: 203.0009407
  			},
  			{
  				nominal: 204,
  				mass: 204.000652
  			},
  			{
  				nominal: 205,
  				mass: 204.9985939
  			},
  			{
  				nominal: 206,
  				mass: 205.998666
  			},
  			{
  				nominal: 207,
  				mass: 206.996946
  			},
  			{
  				nominal: 208,
  				mass: 207.997138
  			},
  			{
  				nominal: 209,
  				mass: 208.995955
  			},
  			{
  				nominal: 210,
  				mass: 209.996422
  			},
  			{
  				nominal: 211,
  				mass: 210.995556
  			},
  			{
  				nominal: 212,
  				mass: 211.9962257
  			},
  			{
  				nominal: 213,
  				mass: 212.996186
  			},
  			{
  				nominal: 214,
  				mass: 213.9989713
  			},
  			{
  				nominal: 215,
  				mass: 215.0003418
  			},
  			{
  				nominal: 216,
  				mass: 216.0031899
  			},
  			{
  				nominal: 217,
  				mass: 217.0046323
  			},
  			{
  				nominal: 218,
  				mass: 218.0075787
  			},
  			{
  				nominal: 219,
  				mass: 219.0092524
  			},
  			{
  				nominal: 220,
  				mass: 220.0123277
  			},
  			{
  				nominal: 221,
  				mass: 221.0142552
  			},
  			{
  				nominal: 222,
  				mass: 222.017552
  			},
  			{
  				nominal: 223,
  				mass: 223.019736
  			},
  			{
  				nominal: 224,
  				mass: 224.023398
  			},
  			{
  				nominal: 225,
  				mass: 225.025573
  			},
  			{
  				nominal: 226,
  				mass: 226.029566
  			},
  			{
  				nominal: 227,
  				mass: 227.031869
  			},
  			{
  				nominal: 228,
  				mass: 228.035823
  			},
  			{
  				nominal: 229,
  				mass: 229.038298
  			},
  			{
  				nominal: 230,
  				mass: 230.042416
  			},
  			{
  				nominal: 231,
  				mass: 231.045158
  			},
  			{
  				nominal: 232,
  				mass: 232.04937
  			},
  			{
  				nominal: 233,
  				mass: 233.05264
  			}
  		],
  		symbol: "Fr",
  		mass: null,
  		name: "Francium"
  	},
  	{
  		number: 88,
  		isotopes: [
  			{
  				nominal: 201,
  				mass: 201.01271
  			},
  			{
  				nominal: 202,
  				mass: 202.00976
  			},
  			{
  				nominal: 203,
  				mass: 203.009304
  			},
  			{
  				nominal: 204,
  				mass: 204.006492
  			},
  			{
  				nominal: 205,
  				mass: 205.006268
  			},
  			{
  				nominal: 206,
  				mass: 206.003828
  			},
  			{
  				nominal: 207,
  				mass: 207.003799
  			},
  			{
  				nominal: 208,
  				mass: 208.001841
  			},
  			{
  				nominal: 209,
  				mass: 209.00199
  			},
  			{
  				nominal: 210,
  				mass: 210.000494
  			},
  			{
  				nominal: 211,
  				mass: 211.0008932
  			},
  			{
  				nominal: 212,
  				mass: 211.999787
  			},
  			{
  				nominal: 213,
  				mass: 213.000384
  			},
  			{
  				nominal: 214,
  				mass: 214.0000997
  			},
  			{
  				nominal: 215,
  				mass: 215.0027204
  			},
  			{
  				nominal: 216,
  				mass: 216.0035334
  			},
  			{
  				nominal: 217,
  				mass: 217.0063207
  			},
  			{
  				nominal: 218,
  				mass: 218.007141
  			},
  			{
  				nominal: 219,
  				mass: 219.0100855
  			},
  			{
  				nominal: 220,
  				mass: 220.0110259
  			},
  			{
  				nominal: 221,
  				mass: 221.0139177
  			},
  			{
  				nominal: 222,
  				mass: 222.0153748
  			},
  			{
  				nominal: 223,
  				mass: 223.0185023
  			},
  			{
  				nominal: 224,
  				mass: 224.020212
  			},
  			{
  				nominal: 225,
  				mass: 225.0236119
  			},
  			{
  				nominal: 226,
  				mass: 226.0254103
  			},
  			{
  				nominal: 227,
  				mass: 227.0291783
  			},
  			{
  				nominal: 228,
  				mass: 228.0310707
  			},
  			{
  				nominal: 229,
  				mass: 229.034942
  			},
  			{
  				nominal: 230,
  				mass: 230.037055
  			},
  			{
  				nominal: 231,
  				mass: 231.041027
  			},
  			{
  				nominal: 232,
  				mass: 232.0434753
  			},
  			{
  				nominal: 233,
  				mass: 233.047582
  			},
  			{
  				nominal: 234,
  				mass: 234.050342
  			},
  			{
  				nominal: 235,
  				mass: 235.05497
  			}
  		],
  		symbol: "Ra",
  		mass: null,
  		name: "Radium"
  	},
  	{
  		number: 89,
  		isotopes: [
  			{
  				nominal: 206,
  				mass: 206.014452
  			},
  			{
  				nominal: 207,
  				mass: 207.011966
  			},
  			{
  				nominal: 208,
  				mass: 208.01155
  			},
  			{
  				nominal: 209,
  				mass: 209.009495
  			},
  			{
  				nominal: 210,
  				mass: 210.009436
  			},
  			{
  				nominal: 211,
  				mass: 211.007732
  			},
  			{
  				nominal: 212,
  				mass: 212.007813
  			},
  			{
  				nominal: 213,
  				mass: 213.006609
  			},
  			{
  				nominal: 214,
  				mass: 214.006918
  			},
  			{
  				nominal: 215,
  				mass: 215.006475
  			},
  			{
  				nominal: 216,
  				mass: 216.008743
  			},
  			{
  				nominal: 217,
  				mass: 217.009344
  			},
  			{
  				nominal: 218,
  				mass: 218.011642
  			},
  			{
  				nominal: 219,
  				mass: 219.012421
  			},
  			{
  				nominal: 220,
  				mass: 220.0147549
  			},
  			{
  				nominal: 221,
  				mass: 221.015592
  			},
  			{
  				nominal: 222,
  				mass: 222.0178442
  			},
  			{
  				nominal: 223,
  				mass: 223.0191377
  			},
  			{
  				nominal: 224,
  				mass: 224.0217232
  			},
  			{
  				nominal: 225,
  				mass: 225.02323
  			},
  			{
  				nominal: 226,
  				mass: 226.0260984
  			},
  			{
  				nominal: 227,
  				mass: 227.0277523
  			},
  			{
  				nominal: 228,
  				mass: 228.0310215
  			},
  			{
  				nominal: 229,
  				mass: 229.032956
  			},
  			{
  				nominal: 230,
  				mass: 230.036327
  			},
  			{
  				nominal: 231,
  				mass: 231.038393
  			},
  			{
  				nominal: 232,
  				mass: 232.042034
  			},
  			{
  				nominal: 233,
  				mass: 233.044346
  			},
  			{
  				nominal: 234,
  				mass: 234.048139
  			},
  			{
  				nominal: 235,
  				mass: 235.05084
  			},
  			{
  				nominal: 236,
  				mass: 236.054988
  			},
  			{
  				nominal: 237,
  				mass: 237.05827
  			}
  		],
  		symbol: "Ac",
  		mass: null,
  		name: "Actinium"
  	},
  	{
  		number: 90,
  		isotopes: [
  			{
  				nominal: 208,
  				mass: 208.0179
  			},
  			{
  				nominal: 209,
  				mass: 209.017753
  			},
  			{
  				nominal: 210,
  				mass: 210.015094
  			},
  			{
  				nominal: 211,
  				mass: 211.014929
  			},
  			{
  				nominal: 212,
  				mass: 212.012988
  			},
  			{
  				nominal: 213,
  				mass: 213.013009
  			},
  			{
  				nominal: 214,
  				mass: 214.0115
  			},
  			{
  				nominal: 215,
  				mass: 215.0117248
  			},
  			{
  				nominal: 216,
  				mass: 216.011056
  			},
  			{
  				nominal: 217,
  				mass: 217.013117
  			},
  			{
  				nominal: 218,
  				mass: 218.013276
  			},
  			{
  				nominal: 219,
  				mass: 219.015537
  			},
  			{
  				nominal: 220,
  				mass: 220.015748
  			},
  			{
  				nominal: 221,
  				mass: 221.018184
  			},
  			{
  				nominal: 222,
  				mass: 222.018469
  			},
  			{
  				nominal: 223,
  				mass: 223.0208119
  			},
  			{
  				nominal: 224,
  				mass: 224.021464
  			},
  			{
  				nominal: 225,
  				mass: 225.0239514
  			},
  			{
  				nominal: 226,
  				mass: 226.0249034
  			},
  			{
  				nominal: 227,
  				mass: 227.0277042
  			},
  			{
  				nominal: 228,
  				mass: 228.0287413
  			},
  			{
  				nominal: 229,
  				mass: 229.0317627
  			},
  			{
  				nominal: 230,
  				mass: 230.0331341
  			},
  			{
  				nominal: 231,
  				mass: 231.0363046
  			},
  			{
  				nominal: 232,
  				mass: 232.0380558,
  				abundance: 1
  			},
  			{
  				nominal: 233,
  				mass: 233.0415823
  			},
  			{
  				nominal: 234,
  				mass: 234.0436014
  			},
  			{
  				nominal: 235,
  				mass: 235.047255
  			},
  			{
  				nominal: 236,
  				mass: 236.049657
  			},
  			{
  				nominal: 237,
  				mass: 237.053629
  			},
  			{
  				nominal: 238,
  				mass: 238.0565
  			},
  			{
  				nominal: 239,
  				mass: 239.06077
  			}
  		],
  		symbol: "Th",
  		mass: 232.0380558,
  		name: "Thorium",
  		monoisotopicMass: 232.0380558
  	},
  	{
  		number: 91,
  		isotopes: [
  			{
  				nominal: 212,
  				mass: 212.023203
  			},
  			{
  				nominal: 213,
  				mass: 213.021109
  			},
  			{
  				nominal: 214,
  				mass: 214.020918
  			},
  			{
  				nominal: 215,
  				mass: 215.019183
  			},
  			{
  				nominal: 216,
  				mass: 216.019109
  			},
  			{
  				nominal: 217,
  				mass: 217.018325
  			},
  			{
  				nominal: 218,
  				mass: 218.020059
  			},
  			{
  				nominal: 219,
  				mass: 219.019904
  			},
  			{
  				nominal: 220,
  				mass: 220.021705
  			},
  			{
  				nominal: 221,
  				mass: 221.021875
  			},
  			{
  				nominal: 222,
  				mass: 222.023784
  			},
  			{
  				nominal: 223,
  				mass: 223.023963
  			},
  			{
  				nominal: 224,
  				mass: 224.0256176
  			},
  			{
  				nominal: 225,
  				mass: 225.026131
  			},
  			{
  				nominal: 226,
  				mass: 226.027948
  			},
  			{
  				nominal: 227,
  				mass: 227.0288054
  			},
  			{
  				nominal: 228,
  				mass: 228.0310517
  			},
  			{
  				nominal: 229,
  				mass: 229.0320972
  			},
  			{
  				nominal: 230,
  				mass: 230.034541
  			},
  			{
  				nominal: 231,
  				mass: 231.0358842,
  				abundance: 1
  			},
  			{
  				nominal: 232,
  				mass: 232.0385917
  			},
  			{
  				nominal: 233,
  				mass: 233.0402472
  			},
  			{
  				nominal: 234,
  				mass: 234.0433072
  			},
  			{
  				nominal: 235,
  				mass: 235.045399
  			},
  			{
  				nominal: 236,
  				mass: 236.048668
  			},
  			{
  				nominal: 237,
  				mass: 237.051023
  			},
  			{
  				nominal: 238,
  				mass: 238.054637
  			},
  			{
  				nominal: 239,
  				mass: 239.05726
  			},
  			{
  				nominal: 240,
  				mass: 240.06098
  			},
  			{
  				nominal: 241,
  				mass: 241.06408
  			}
  		],
  		symbol: "Pa",
  		mass: 231.0358842,
  		name: "Protactinium",
  		monoisotopicMass: 231.0358842
  	},
  	{
  		number: 92,
  		isotopes: [
  			{
  				nominal: 217,
  				mass: 217.02466
  			},
  			{
  				nominal: 218,
  				mass: 218.023523
  			},
  			{
  				nominal: 219,
  				mass: 219.024999
  			},
  			{
  				nominal: 220,
  				mass: 220.02462
  			},
  			{
  				nominal: 221,
  				mass: 221.02628
  			},
  			{
  				nominal: 222,
  				mass: 222.026
  			},
  			{
  				nominal: 223,
  				mass: 223.027739
  			},
  			{
  				nominal: 224,
  				mass: 224.027605
  			},
  			{
  				nominal: 225,
  				mass: 225.029391
  			},
  			{
  				nominal: 226,
  				mass: 226.029339
  			},
  			{
  				nominal: 227,
  				mass: 227.031157
  			},
  			{
  				nominal: 228,
  				mass: 228.031371
  			},
  			{
  				nominal: 229,
  				mass: 229.0335063
  			},
  			{
  				nominal: 230,
  				mass: 230.0339401
  			},
  			{
  				nominal: 231,
  				mass: 231.0362939
  			},
  			{
  				nominal: 232,
  				mass: 232.0371563
  			},
  			{
  				nominal: 233,
  				mass: 233.0396355
  			},
  			{
  				nominal: 234,
  				mass: 234.0409523,
  				abundance: 0.000054
  			},
  			{
  				nominal: 235,
  				mass: 235.0439301,
  				abundance: 0.007204
  			},
  			{
  				nominal: 236,
  				mass: 236.0455682
  			},
  			{
  				nominal: 237,
  				mass: 237.0487304
  			},
  			{
  				nominal: 238,
  				mass: 238.0507884,
  				abundance: 0.992742
  			},
  			{
  				nominal: 239,
  				mass: 239.0542935
  			},
  			{
  				nominal: 240,
  				mass: 240.0565934
  			},
  			{
  				nominal: 241,
  				mass: 241.06033
  			},
  			{
  				nominal: 242,
  				mass: 242.06293
  			},
  			{
  				nominal: 243,
  				mass: 243.06699
  			}
  		],
  		symbol: "U",
  		mass: 238.0289104616574,
  		name: "Uranium",
  		monoisotopicMass: 238.0507884
  	},
  	{
  		number: 93,
  		isotopes: [
  			{
  				nominal: 219,
  				mass: 219.03143
  			},
  			{
  				nominal: 220,
  				mass: 220.03254
  			},
  			{
  				nominal: 221,
  				mass: 221.03204
  			},
  			{
  				nominal: 222,
  				mass: 222.0333
  			},
  			{
  				nominal: 223,
  				mass: 223.03285
  			},
  			{
  				nominal: 224,
  				mass: 224.03422
  			},
  			{
  				nominal: 225,
  				mass: 225.033911
  			},
  			{
  				nominal: 226,
  				mass: 226.035188
  			},
  			{
  				nominal: 227,
  				mass: 227.034957
  			},
  			{
  				nominal: 228,
  				mass: 228.036067
  			},
  			{
  				nominal: 229,
  				mass: 229.036264
  			},
  			{
  				nominal: 230,
  				mass: 230.037828
  			},
  			{
  				nominal: 231,
  				mass: 231.038245
  			},
  			{
  				nominal: 232,
  				mass: 232.04011
  			},
  			{
  				nominal: 233,
  				mass: 233.040741
  			},
  			{
  				nominal: 234,
  				mass: 234.0428953
  			},
  			{
  				nominal: 235,
  				mass: 235.0440635
  			},
  			{
  				nominal: 236,
  				mass: 236.04657
  			},
  			{
  				nominal: 237,
  				mass: 237.0481736
  			},
  			{
  				nominal: 238,
  				mass: 238.0509466
  			},
  			{
  				nominal: 239,
  				mass: 239.0529392
  			},
  			{
  				nominal: 240,
  				mass: 240.056165
  			},
  			{
  				nominal: 241,
  				mass: 241.058253
  			},
  			{
  				nominal: 242,
  				mass: 242.06164
  			},
  			{
  				nominal: 243,
  				mass: 243.06428
  			},
  			{
  				nominal: 244,
  				mass: 244.06785
  			},
  			{
  				nominal: 245,
  				mass: 245.0708
  			}
  		],
  		symbol: "Np",
  		mass: null,
  		name: "Neptunium"
  	},
  	{
  		number: 94,
  		isotopes: [
  			{
  				nominal: 228,
  				mass: 228.038732
  			},
  			{
  				nominal: 229,
  				mass: 229.040144
  			},
  			{
  				nominal: 230,
  				mass: 230.03965
  			},
  			{
  				nominal: 231,
  				mass: 231.041102
  			},
  			{
  				nominal: 232,
  				mass: 232.041185
  			},
  			{
  				nominal: 233,
  				mass: 233.042998
  			},
  			{
  				nominal: 234,
  				mass: 234.0433174
  			},
  			{
  				nominal: 235,
  				mass: 235.045286
  			},
  			{
  				nominal: 236,
  				mass: 236.0460581
  			},
  			{
  				nominal: 237,
  				mass: 237.0484098
  			},
  			{
  				nominal: 238,
  				mass: 238.0495601
  			},
  			{
  				nominal: 239,
  				mass: 239.0521636
  			},
  			{
  				nominal: 240,
  				mass: 240.0538138
  			},
  			{
  				nominal: 241,
  				mass: 241.0568517
  			},
  			{
  				nominal: 242,
  				mass: 242.0587428
  			},
  			{
  				nominal: 243,
  				mass: 243.0620036
  			},
  			{
  				nominal: 244,
  				mass: 244.0642053
  			},
  			{
  				nominal: 245,
  				mass: 245.067826
  			},
  			{
  				nominal: 246,
  				mass: 246.070205
  			},
  			{
  				nominal: 247,
  				mass: 247.07419
  			}
  		],
  		symbol: "Pu",
  		mass: null,
  		name: "Plutonium"
  	},
  	{
  		number: 95,
  		isotopes: [
  			{
  				nominal: 230,
  				mass: 230.04609
  			},
  			{
  				nominal: 231,
  				mass: 231.04556
  			},
  			{
  				nominal: 232,
  				mass: 232.04645
  			},
  			{
  				nominal: 233,
  				mass: 233.04644
  			},
  			{
  				nominal: 234,
  				mass: 234.04773
  			},
  			{
  				nominal: 235,
  				mass: 235.047908
  			},
  			{
  				nominal: 236,
  				mass: 236.04943
  			},
  			{
  				nominal: 237,
  				mass: 237.049996
  			},
  			{
  				nominal: 238,
  				mass: 238.051985
  			},
  			{
  				nominal: 239,
  				mass: 239.0530247
  			},
  			{
  				nominal: 240,
  				mass: 240.0553
  			},
  			{
  				nominal: 241,
  				mass: 241.0568293
  			},
  			{
  				nominal: 242,
  				mass: 242.0595494
  			},
  			{
  				nominal: 243,
  				mass: 243.0613813
  			},
  			{
  				nominal: 244,
  				mass: 244.0642851
  			},
  			{
  				nominal: 245,
  				mass: 245.0664548
  			},
  			{
  				nominal: 246,
  				mass: 246.069775
  			},
  			{
  				nominal: 247,
  				mass: 247.07209
  			},
  			{
  				nominal: 248,
  				mass: 248.07575
  			},
  			{
  				nominal: 249,
  				mass: 249.07848
  			}
  		],
  		symbol: "Am",
  		name: "Americium",
  		mass: null
  	},
  	{
  		number: 96,
  		isotopes: [
  			{
  				nominal: 232,
  				mass: 232.04982
  			},
  			{
  				nominal: 233,
  				mass: 233.05077
  			},
  			{
  				nominal: 234,
  				mass: 234.05016
  			},
  			{
  				nominal: 235,
  				mass: 235.05154
  			},
  			{
  				nominal: 236,
  				mass: 236.051374
  			},
  			{
  				nominal: 237,
  				mass: 237.052869
  			},
  			{
  				nominal: 238,
  				mass: 238.053081
  			},
  			{
  				nominal: 239,
  				mass: 239.05491
  			},
  			{
  				nominal: 240,
  				mass: 240.0555297
  			},
  			{
  				nominal: 241,
  				mass: 241.0576532
  			},
  			{
  				nominal: 242,
  				mass: 242.058836
  			},
  			{
  				nominal: 243,
  				mass: 243.0613893
  			},
  			{
  				nominal: 244,
  				mass: 244.0627528
  			},
  			{
  				nominal: 245,
  				mass: 245.0654915
  			},
  			{
  				nominal: 246,
  				mass: 246.0672238
  			},
  			{
  				nominal: 247,
  				mass: 247.0703541
  			},
  			{
  				nominal: 248,
  				mass: 248.0723499
  			},
  			{
  				nominal: 249,
  				mass: 249.0759548
  			},
  			{
  				nominal: 250,
  				mass: 250.078358
  			},
  			{
  				nominal: 251,
  				mass: 251.082286
  			},
  			{
  				nominal: 252,
  				mass: 252.08487
  			}
  		],
  		symbol: "Cm",
  		name: "Curium",
  		mass: null
  	},
  	{
  		number: 97,
  		isotopes: [
  			{
  				nominal: 234,
  				mass: 234.05727
  			},
  			{
  				nominal: 235,
  				mass: 235.05658
  			},
  			{
  				nominal: 236,
  				mass: 236.05748
  			},
  			{
  				nominal: 237,
  				mass: 237.0571
  			},
  			{
  				nominal: 238,
  				mass: 238.0582
  			},
  			{
  				nominal: 239,
  				mass: 239.05824
  			},
  			{
  				nominal: 240,
  				mass: 240.05976
  			},
  			{
  				nominal: 241,
  				mass: 241.06016
  			},
  			{
  				nominal: 242,
  				mass: 242.06198
  			},
  			{
  				nominal: 243,
  				mass: 243.0630078
  			},
  			{
  				nominal: 244,
  				mass: 244.065181
  			},
  			{
  				nominal: 245,
  				mass: 245.0663618
  			},
  			{
  				nominal: 246,
  				mass: 246.068673
  			},
  			{
  				nominal: 247,
  				mass: 247.0703073
  			},
  			{
  				nominal: 248,
  				mass: 248.073088
  			},
  			{
  				nominal: 249,
  				mass: 249.0749877
  			},
  			{
  				nominal: 250,
  				mass: 250.0783167
  			},
  			{
  				nominal: 251,
  				mass: 251.080762
  			},
  			{
  				nominal: 252,
  				mass: 252.08431
  			},
  			{
  				nominal: 253,
  				mass: 253.08688
  			},
  			{
  				nominal: 254,
  				mass: 254.0906
  			}
  		],
  		symbol: "Bk",
  		name: "Berkelium",
  		mass: null
  	},
  	{
  		number: 98,
  		isotopes: [
  			{
  				nominal: 237,
  				mass: 237.062198
  			},
  			{
  				nominal: 238,
  				mass: 238.06149
  			},
  			{
  				nominal: 239,
  				mass: 239.06253
  			},
  			{
  				nominal: 240,
  				mass: 240.062256
  			},
  			{
  				nominal: 241,
  				mass: 241.06369
  			},
  			{
  				nominal: 242,
  				mass: 242.063754
  			},
  			{
  				nominal: 243,
  				mass: 243.06548
  			},
  			{
  				nominal: 244,
  				mass: 244.0660008
  			},
  			{
  				nominal: 245,
  				mass: 245.0680487
  			},
  			{
  				nominal: 246,
  				mass: 246.0688055
  			},
  			{
  				nominal: 247,
  				mass: 247.070965
  			},
  			{
  				nominal: 248,
  				mass: 248.0721851
  			},
  			{
  				nominal: 249,
  				mass: 249.0748539
  			},
  			{
  				nominal: 250,
  				mass: 250.0764062
  			},
  			{
  				nominal: 251,
  				mass: 251.0795886
  			},
  			{
  				nominal: 252,
  				mass: 252.0816272
  			},
  			{
  				nominal: 253,
  				mass: 253.0851345
  			},
  			{
  				nominal: 254,
  				mass: 254.087324
  			},
  			{
  				nominal: 255,
  				mass: 255.09105
  			},
  			{
  				nominal: 256,
  				mass: 256.09344
  			}
  		],
  		symbol: "Cf",
  		name: "Californium",
  		mass: null
  	},
  	{
  		number: 99,
  		isotopes: [
  			{
  				nominal: 239,
  				mass: 239.06823
  			},
  			{
  				nominal: 240,
  				mass: 240.06892
  			},
  			{
  				nominal: 241,
  				mass: 241.06856
  			},
  			{
  				nominal: 242,
  				mass: 242.06957
  			},
  			{
  				nominal: 243,
  				mass: 243.06951
  			},
  			{
  				nominal: 244,
  				mass: 244.07088
  			},
  			{
  				nominal: 245,
  				mass: 245.07125
  			},
  			{
  				nominal: 246,
  				mass: 246.0729
  			},
  			{
  				nominal: 247,
  				mass: 247.073622
  			},
  			{
  				nominal: 248,
  				mass: 248.075471
  			},
  			{
  				nominal: 249,
  				mass: 249.076411
  			},
  			{
  				nominal: 250,
  				mass: 250.07861
  			},
  			{
  				nominal: 251,
  				mass: 251.0799936
  			},
  			{
  				nominal: 252,
  				mass: 252.08298
  			},
  			{
  				nominal: 253,
  				mass: 253.0848257
  			},
  			{
  				nominal: 254,
  				mass: 254.0880222
  			},
  			{
  				nominal: 255,
  				mass: 255.090275
  			},
  			{
  				nominal: 256,
  				mass: 256.0936
  			},
  			{
  				nominal: 257,
  				mass: 257.09598
  			},
  			{
  				nominal: 258,
  				mass: 258.09952
  			}
  		],
  		symbol: "Es",
  		name: "Einsteinium",
  		mass: null
  	},
  	{
  		number: 100,
  		isotopes: [
  			{
  				nominal: 241,
  				mass: 241.07421
  			},
  			{
  				nominal: 242,
  				mass: 242.07343
  			},
  			{
  				nominal: 243,
  				mass: 243.07446
  			},
  			{
  				nominal: 244,
  				mass: 244.07404
  			},
  			{
  				nominal: 245,
  				mass: 245.07535
  			},
  			{
  				nominal: 246,
  				mass: 246.07535
  			},
  			{
  				nominal: 247,
  				mass: 247.07694
  			},
  			{
  				nominal: 248,
  				mass: 248.0771865
  			},
  			{
  				nominal: 249,
  				mass: 249.0789275
  			},
  			{
  				nominal: 250,
  				mass: 250.079521
  			},
  			{
  				nominal: 251,
  				mass: 251.08154
  			},
  			{
  				nominal: 252,
  				mass: 252.0824671
  			},
  			{
  				nominal: 253,
  				mass: 253.0851846
  			},
  			{
  				nominal: 254,
  				mass: 254.0868544
  			},
  			{
  				nominal: 255,
  				mass: 255.089964
  			},
  			{
  				nominal: 256,
  				mass: 256.0917745
  			},
  			{
  				nominal: 257,
  				mass: 257.0951061
  			},
  			{
  				nominal: 258,
  				mass: 258.09708
  			},
  			{
  				nominal: 259,
  				mass: 259.1006
  			},
  			{
  				nominal: 260,
  				mass: 260.10281
  			}
  		],
  		symbol: "Fm",
  		name: "Fermium",
  		mass: null
  	},
  	{
  		number: 101,
  		isotopes: [
  			{
  				nominal: 245,
  				mass: 245.08081
  			},
  			{
  				nominal: 246,
  				mass: 246.08171
  			},
  			{
  				nominal: 247,
  				mass: 247.08152
  			},
  			{
  				nominal: 248,
  				mass: 248.08282
  			},
  			{
  				nominal: 249,
  				mass: 249.08291
  			},
  			{
  				nominal: 250,
  				mass: 250.08441
  			},
  			{
  				nominal: 251,
  				mass: 251.084774
  			},
  			{
  				nominal: 252,
  				mass: 252.08643
  			},
  			{
  				nominal: 253,
  				mass: 253.087144
  			},
  			{
  				nominal: 254,
  				mass: 254.08959
  			},
  			{
  				nominal: 255,
  				mass: 255.0910841
  			},
  			{
  				nominal: 256,
  				mass: 256.09389
  			},
  			{
  				nominal: 257,
  				mass: 257.0955424
  			},
  			{
  				nominal: 258,
  				mass: 258.0984315
  			},
  			{
  				nominal: 259,
  				mass: 259.10051
  			},
  			{
  				nominal: 260,
  				mass: 260.10365
  			},
  			{
  				nominal: 261,
  				mass: 261.10583
  			},
  			{
  				nominal: 262,
  				mass: 262.1091
  			}
  		],
  		symbol: "Md",
  		name: "Mendelevium",
  		mass: null
  	},
  	{
  		number: 102,
  		isotopes: [
  			{
  				nominal: 248,
  				mass: 248.08655
  			},
  			{
  				nominal: 249,
  				mass: 249.0878
  			},
  			{
  				nominal: 250,
  				mass: 250.08756
  			},
  			{
  				nominal: 251,
  				mass: 251.08894
  			},
  			{
  				nominal: 252,
  				mass: 252.088967
  			},
  			{
  				nominal: 253,
  				mass: 253.0905641
  			},
  			{
  				nominal: 254,
  				mass: 254.090956
  			},
  			{
  				nominal: 255,
  				mass: 255.093191
  			},
  			{
  				nominal: 256,
  				mass: 256.0942829
  			},
  			{
  				nominal: 257,
  				mass: 257.0968878
  			},
  			{
  				nominal: 258,
  				mass: 258.09821
  			},
  			{
  				nominal: 259,
  				mass: 259.10103
  			},
  			{
  				nominal: 260,
  				mass: 260.10264
  			},
  			{
  				nominal: 261,
  				mass: 261.1057
  			},
  			{
  				nominal: 262,
  				mass: 262.10746
  			},
  			{
  				nominal: 263,
  				mass: 263.11071
  			},
  			{
  				nominal: 264,
  				mass: 264.11273
  			}
  		],
  		symbol: "No",
  		name: "Nobelium",
  		mass: null
  	},
  	{
  		number: 103,
  		isotopes: [
  			{
  				nominal: 251,
  				mass: 251.09418
  			},
  			{
  				nominal: 252,
  				mass: 252.09526
  			},
  			{
  				nominal: 253,
  				mass: 253.09509
  			},
  			{
  				nominal: 254,
  				mass: 254.09648
  			},
  			{
  				nominal: 255,
  				mass: 255.096562
  			},
  			{
  				nominal: 256,
  				mass: 256.098494
  			},
  			{
  				nominal: 257,
  				mass: 257.099418
  			},
  			{
  				nominal: 258,
  				mass: 258.10176
  			},
  			{
  				nominal: 259,
  				mass: 259.102902
  			},
  			{
  				nominal: 260,
  				mass: 260.1055
  			},
  			{
  				nominal: 261,
  				mass: 261.10688
  			},
  			{
  				nominal: 262,
  				mass: 262.10961
  			},
  			{
  				nominal: 263,
  				mass: 263.11136
  			},
  			{
  				nominal: 264,
  				mass: 264.1142
  			},
  			{
  				nominal: 265,
  				mass: 265.11619
  			},
  			{
  				nominal: 266,
  				mass: 266.11983
  			}
  		],
  		symbol: "Lr",
  		name: "Lawrencium",
  		mass: null
  	},
  	{
  		number: 104,
  		isotopes: [
  			{
  				nominal: 253,
  				mass: 253.10044
  			},
  			{
  				nominal: 254,
  				mass: 254.10005
  			},
  			{
  				nominal: 255,
  				mass: 255.10127
  			},
  			{
  				nominal: 256,
  				mass: 256.101152
  			},
  			{
  				nominal: 257,
  				mass: 257.102918
  			},
  			{
  				nominal: 258,
  				mass: 258.103428
  			},
  			{
  				nominal: 259,
  				mass: 259.105596
  			},
  			{
  				nominal: 260,
  				mass: 260.10644
  			},
  			{
  				nominal: 261,
  				mass: 261.108773
  			},
  			{
  				nominal: 262,
  				mass: 262.10992
  			},
  			{
  				nominal: 263,
  				mass: 263.11249
  			},
  			{
  				nominal: 264,
  				mass: 264.11388
  			},
  			{
  				nominal: 265,
  				mass: 265.11668
  			},
  			{
  				nominal: 266,
  				mass: 266.11817
  			},
  			{
  				nominal: 267,
  				mass: 267.12179
  			},
  			{
  				nominal: 268,
  				mass: 268.12397
  			}
  		],
  		symbol: "Rf",
  		name: "Rutherfordium",
  		mass: null
  	},
  	{
  		number: 105,
  		isotopes: [
  			{
  				nominal: 255,
  				mass: 255.10707
  			},
  			{
  				nominal: 256,
  				mass: 256.10789
  			},
  			{
  				nominal: 257,
  				mass: 257.10758
  			},
  			{
  				nominal: 258,
  				mass: 258.10928
  			},
  			{
  				nominal: 259,
  				mass: 259.109492
  			},
  			{
  				nominal: 260,
  				mass: 260.1113
  			},
  			{
  				nominal: 261,
  				mass: 261.11192
  			},
  			{
  				nominal: 262,
  				mass: 262.11407
  			},
  			{
  				nominal: 263,
  				mass: 263.11499
  			},
  			{
  				nominal: 264,
  				mass: 264.11741
  			},
  			{
  				nominal: 265,
  				mass: 265.11861
  			},
  			{
  				nominal: 266,
  				mass: 266.12103
  			},
  			{
  				nominal: 267,
  				mass: 267.12247
  			},
  			{
  				nominal: 268,
  				mass: 268.12567
  			},
  			{
  				nominal: 269,
  				mass: 269.12791
  			},
  			{
  				nominal: 270,
  				mass: 270.13136
  			}
  		],
  		symbol: "Db",
  		name: "Dubnium",
  		mass: null
  	},
  	{
  		number: 106,
  		isotopes: [
  			{
  				nominal: 258,
  				mass: 258.11298
  			},
  			{
  				nominal: 259,
  				mass: 259.1144
  			},
  			{
  				nominal: 260,
  				mass: 260.114384
  			},
  			{
  				nominal: 261,
  				mass: 261.115949
  			},
  			{
  				nominal: 262,
  				mass: 262.116337
  			},
  			{
  				nominal: 263,
  				mass: 263.11829
  			},
  			{
  				nominal: 264,
  				mass: 264.11893
  			},
  			{
  				nominal: 265,
  				mass: 265.12109
  			},
  			{
  				nominal: 266,
  				mass: 266.12198
  			},
  			{
  				nominal: 267,
  				mass: 267.12436
  			},
  			{
  				nominal: 268,
  				mass: 268.12539
  			},
  			{
  				nominal: 269,
  				mass: 269.12863
  			},
  			{
  				nominal: 270,
  				mass: 270.13043
  			},
  			{
  				nominal: 271,
  				mass: 271.13393
  			},
  			{
  				nominal: 272,
  				mass: 272.13589
  			},
  			{
  				nominal: 273,
  				mass: 273.13958
  			}
  		],
  		symbol: "Sg",
  		name: "Seaborgium",
  		mass: null
  	},
  	{
  		number: 107,
  		isotopes: [
  			{
  				nominal: 260,
  				mass: 260.12166
  			},
  			{
  				nominal: 261,
  				mass: 261.12145
  			},
  			{
  				nominal: 262,
  				mass: 262.12297
  			},
  			{
  				nominal: 263,
  				mass: 263.12292
  			},
  			{
  				nominal: 264,
  				mass: 264.12459
  			},
  			{
  				nominal: 265,
  				mass: 265.12491
  			},
  			{
  				nominal: 266,
  				mass: 266.12679
  			},
  			{
  				nominal: 267,
  				mass: 267.1275
  			},
  			{
  				nominal: 268,
  				mass: 268.12969
  			},
  			{
  				nominal: 269,
  				mass: 269.13042
  			},
  			{
  				nominal: 270,
  				mass: 270.13336
  			},
  			{
  				nominal: 271,
  				mass: 271.13526
  			},
  			{
  				nominal: 272,
  				mass: 272.13826
  			},
  			{
  				nominal: 273,
  				mass: 273.14024
  			},
  			{
  				nominal: 274,
  				mass: 274.14355
  			},
  			{
  				nominal: 275,
  				mass: 275.14567
  			}
  		],
  		symbol: "Bh",
  		name: "Bohrium",
  		mass: null
  	},
  	{
  		number: 108,
  		isotopes: [
  			{
  				nominal: 263,
  				mass: 263.12852
  			},
  			{
  				nominal: 264,
  				mass: 264.128357
  			},
  			{
  				nominal: 265,
  				mass: 265.129793
  			},
  			{
  				nominal: 266,
  				mass: 266.130046
  			},
  			{
  				nominal: 267,
  				mass: 267.13167
  			},
  			{
  				nominal: 268,
  				mass: 268.13186
  			},
  			{
  				nominal: 269,
  				mass: 269.13375
  			},
  			{
  				nominal: 270,
  				mass: 270.13429
  			},
  			{
  				nominal: 271,
  				mass: 271.13717
  			},
  			{
  				nominal: 272,
  				mass: 272.1385
  			},
  			{
  				nominal: 273,
  				mass: 273.14168
  			},
  			{
  				nominal: 274,
  				mass: 274.1433
  			},
  			{
  				nominal: 275,
  				mass: 275.14667
  			},
  			{
  				nominal: 276,
  				mass: 276.14846
  			},
  			{
  				nominal: 277,
  				mass: 277.1519
  			}
  		],
  		symbol: "Hs",
  		name: "Hassium",
  		mass: null
  	},
  	{
  		number: 109,
  		isotopes: [
  			{
  				nominal: 265,
  				mass: 265.136
  			},
  			{
  				nominal: 266,
  				mass: 266.13737
  			},
  			{
  				nominal: 267,
  				mass: 267.13719
  			},
  			{
  				nominal: 268,
  				mass: 268.13865
  			},
  			{
  				nominal: 269,
  				mass: 269.13882
  			},
  			{
  				nominal: 270,
  				mass: 270.14033
  			},
  			{
  				nominal: 271,
  				mass: 271.14074
  			},
  			{
  				nominal: 272,
  				mass: 272.14341
  			},
  			{
  				nominal: 273,
  				mass: 273.1444
  			},
  			{
  				nominal: 274,
  				mass: 274.14724
  			},
  			{
  				nominal: 275,
  				mass: 275.14882
  			},
  			{
  				nominal: 276,
  				mass: 276.15159
  			},
  			{
  				nominal: 277,
  				mass: 277.15327
  			},
  			{
  				nominal: 278,
  				mass: 278.15631
  			},
  			{
  				nominal: 279,
  				mass: 279.15808
  			}
  		],
  		symbol: "Mt",
  		name: "Meitnerium",
  		mass: null
  	},
  	{
  		number: 110,
  		isotopes: [
  			{
  				nominal: 267,
  				mass: 267.14377
  			},
  			{
  				nominal: 268,
  				mass: 268.14348
  			},
  			{
  				nominal: 269,
  				mass: 269.144752
  			},
  			{
  				nominal: 270,
  				mass: 270.144584
  			},
  			{
  				nominal: 271,
  				mass: 271.14595
  			},
  			{
  				nominal: 272,
  				mass: 272.14602
  			},
  			{
  				nominal: 273,
  				mass: 273.14856
  			},
  			{
  				nominal: 274,
  				mass: 274.14941
  			},
  			{
  				nominal: 275,
  				mass: 275.15203
  			},
  			{
  				nominal: 276,
  				mass: 276.15303
  			},
  			{
  				nominal: 277,
  				mass: 277.15591
  			},
  			{
  				nominal: 278,
  				mass: 278.15704
  			},
  			{
  				nominal: 279,
  				mass: 279.1601
  			},
  			{
  				nominal: 280,
  				mass: 280.16131
  			},
  			{
  				nominal: 281,
  				mass: 281.16451
  			}
  		],
  		symbol: "Ds",
  		name: "Darmstadtium",
  		mass: null
  	},
  	{
  		number: 111,
  		isotopes: [
  			{
  				nominal: 272,
  				mass: 272.15327
  			},
  			{
  				nominal: 273,
  				mass: 273.15313
  			},
  			{
  				nominal: 274,
  				mass: 274.15525
  			},
  			{
  				nominal: 275,
  				mass: 275.15594
  			},
  			{
  				nominal: 276,
  				mass: 276.15833
  			},
  			{
  				nominal: 277,
  				mass: 277.15907
  			},
  			{
  				nominal: 278,
  				mass: 278.16149
  			},
  			{
  				nominal: 279,
  				mass: 279.16272
  			},
  			{
  				nominal: 280,
  				mass: 280.16514
  			},
  			{
  				nominal: 281,
  				mass: 281.16636
  			},
  			{
  				nominal: 282,
  				mass: 282.16912
  			},
  			{
  				nominal: 283,
  				mass: 283.17054
  			}
  		],
  		symbol: "Rg",
  		name: "Roentgenium",
  		mass: null
  	},
  	{
  		number: 112,
  		isotopes: [
  			{
  				nominal: 276,
  				mass: 276.16141
  			},
  			{
  				nominal: 277,
  				mass: 277.16364
  			},
  			{
  				nominal: 278,
  				mass: 278.16416
  			},
  			{
  				nominal: 279,
  				mass: 279.16654
  			},
  			{
  				nominal: 280,
  				mass: 280.16715
  			},
  			{
  				nominal: 281,
  				mass: 281.16975
  			},
  			{
  				nominal: 282,
  				mass: 282.1705
  			},
  			{
  				nominal: 283,
  				mass: 283.17327
  			},
  			{
  				nominal: 284,
  				mass: 284.17416
  			},
  			{
  				nominal: 285,
  				mass: 285.17712
  			}
  		],
  		symbol: "Cn",
  		name: "Copernicium",
  		mass: null
  	},
  	{
  		number: 113,
  		isotopes: [
  			{
  				nominal: 278,
  				mass: 278.17058
  			},
  			{
  				nominal: 279,
  				mass: 279.17095
  			},
  			{
  				nominal: 280,
  				mass: 280.17293
  			},
  			{
  				nominal: 281,
  				mass: 281.17348
  			},
  			{
  				nominal: 282,
  				mass: 282.17567
  			},
  			{
  				nominal: 283,
  				mass: 283.17657
  			},
  			{
  				nominal: 284,
  				mass: 284.17873
  			},
  			{
  				nominal: 285,
  				mass: 285.17973
  			},
  			{
  				nominal: 286,
  				mass: 286.18221
  			},
  			{
  				nominal: 287,
  				mass: 287.18339
  			}
  		],
  		symbol: "Nh",
  		name: "Nihonium",
  		mass: null
  	},
  	{
  		number: 114,
  		isotopes: [
  			{
  				nominal: 285,
  				mass: 285.18364
  			},
  			{
  				nominal: 286,
  				mass: 286.18423
  			},
  			{
  				nominal: 287,
  				mass: 287.18678
  			},
  			{
  				nominal: 288,
  				mass: 288.18757
  			},
  			{
  				nominal: 289,
  				mass: 289.19042
  			}
  		],
  		symbol: "Fl",
  		name: "Flerovium",
  		mass: null
  	},
  	{
  		number: 115,
  		isotopes: [
  			{
  				nominal: 287,
  				mass: 287.1907
  			},
  			{
  				nominal: 288,
  				mass: 288.19274
  			},
  			{
  				nominal: 289,
  				mass: 289.19363
  			},
  			{
  				nominal: 290,
  				mass: 290.19598
  			},
  			{
  				nominal: 291,
  				mass: 291.19707
  			}
  		],
  		symbol: "Mc",
  		name: "Moscovium",
  		mass: null
  	},
  	{
  		number: 116,
  		isotopes: [
  			{
  				nominal: 289,
  				mass: 289.19816
  			},
  			{
  				nominal: 290,
  				mass: 290.19864
  			},
  			{
  				nominal: 291,
  				mass: 291.20108
  			},
  			{
  				nominal: 292,
  				mass: 292.20174
  			},
  			{
  				nominal: 293,
  				mass: 293.20449
  			}
  		],
  		symbol: "Lv",
  		name: "Livermorium",
  		mass: null
  	},
  	{
  		number: 117,
  		isotopes: [
  			{
  				nominal: 291,
  				mass: 291.20553
  			},
  			{
  				nominal: 292,
  				mass: 292.20746
  			},
  			{
  				nominal: 293,
  				mass: 293.20824
  			},
  			{
  				nominal: 294,
  				mass: 294.21046
  			}
  		],
  		symbol: "Ts",
  		name: "Teennessine",
  		mass: null
  	},
  	{
  		number: 118,
  		isotopes: [
  			{
  				nominal: 293,
  				mass: 293.21356
  			},
  			{
  				nominal: 294,
  				mass: 294.21392
  			},
  			{
  				nominal: 295,
  				mass: 295.21624
  			}
  		],
  		symbol: "Og",
  		name: "Oganesson",
  		mass: null
  	}
  ];

  const elements$4 = JSON.parse(JSON.stringify(elements$5));
  elements$4.forEach(element => {
    element.isotopes = element.isotopes.filter(i => i.abundance > 0);
  });
  var elementsAndStableIsotopes = elements$4;

  let elementsAndStableIsotopesObject = {};
  elementsAndStableIsotopes.forEach(element => {
    elementsAndStableIsotopesObject[element.symbol] = element;
  });
  var elementsAndStableIsotopesObject_1 = elementsAndStableIsotopesObject;

  const elements$3 = Object.keys(elementsAndStableIsotopesObject_1).sort((a, b) => b.length - a.length);
  /**
   * Ensure that the mf has been entered with capital letters and not only lowercase
   * If there is only lowercase we try to capitalize the mf
   * @param {string} mf
   */

  function capitalize$1(mf) {
    for (let i = 0; i < mf.length; i++) {
      if (mf.charCodeAt(i) > 64 && mf.charCodeAt(i) < 91) {
        return mf;
      }
    }

    let parts = mf.replace(/([a-z]*)([^a-z]*)/g, '$1 $2 ').split(/ +/);

    for (let i = 0; i < parts.length; i++) {
      if (parts[i].match(/^[a-z]$/)) {
        parts[i] = parts[i].toUpperCase();
      } else if (parts[i].match(/^[a-z]+$/)) {
        let newPart = '';

        for (let j = 0; j < parts[i].length; j++) {
          let two = parts[i].substr(j, 2);
          let one = parts[i].charAt(j).toUpperCase();

          if (['c', 'h', 'o', 'n'].includes(two.charAt(0)) && ['h', 'o', 'n'].includes(two.charAt(1))) {
            newPart += two.toUpperCase();
            j++;
          } else {
            two = two.charAt(0).toUpperCase() + two.charAt(1);

            if (elements$3.includes(two)) {
              newPart += two;
              j++;
            } else {
              if (elements$3.includes(one)) {
                newPart += one;
              } else {
                return mf;
              }
            }
          }
        }

        parts[i] = newPart;
      }
    }

    return parts.join('');
  }

  var ensureCase = capitalize$1;

  const data$2 = elements$5.map(element => ({
    number: element.number,
    symbol: element.symbol,
    mass: element.mass,
    name: element.name,
    monoisotopicMass: element.monoisotopicMass
  }));
  var elements_1 = data$2;

  var elementsAndIsotopes = elements$5;

  let elementsAndIsotopesObject = {};
  elements$5.forEach(element => {
    elementsAndIsotopesObject[element.symbol] = element;
  });
  var elementsAndIsotopesObject_1 = elementsAndIsotopesObject;

  let elementsObject = {};
  elements_1.forEach(element => {
    elementsObject[element.symbol] = element;
  });
  var elementsObject_1 = elementsObject;

  const {
    ELECTRON_MASS: ELECTRON_MASS$6
  } = constants;
  var src$j = {
    elements: elements_1,
    elementsObject: elementsObject_1,
    elementsAndIsotopes,
    elementsAndIsotopesObject: elementsAndIsotopesObject_1,
    elementsAndStableIsotopes,
    elementsAndStableIsotopesObject: elementsAndStableIsotopesObject_1,
    ELECTRON_MASS: ELECTRON_MASS$6
  };

  var groupsObject = {
    "Abu": {
      "name": "2-Aminobutyric acid diradical",
      "mf": "C4H7NO",
      "kind": "",
      "ocl": {
        "value": "dazHPBPOEgEInVZjcH@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGt"
      },
      "mass": 85.10463700109551,
      "monoisotopicMass": 85.05276384961,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Acet": {
      "name": "Acetyl",
      "mf": "C2H3O",
      "kind": "",
      "ocl": {
        "value": "gCaHDEeIi`@",
        "coordinates": "!BbOq~@Ha}"
      },
      "mass": 43.04469897995611,
      "monoisotopicMass": 43.01838971626,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 2
      }, {
        "symbol": "H",
        "number": 3
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Acm": {
      "name": "Acetamidomethyl",
      "mf": "C3H6NO",
      "kind": "",
      "ocl": {
        "value": "gGYHDPliJuS@@",
        "coordinates": "!BbOrH_Xc|_`BH_P"
      },
      "mass": 72.08596035030448,
      "monoisotopicMass": 72.04493881738,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 3
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Adao": {
      "name": "Adamantyloxy",
      "mf": "C10H15O",
      "kind": "",
      "ocl": {
        "value": "dc\\H`HAYRVeV^dUGZjjjj@@",
        "coordinates": "!B]BOXN`EP}CdB\\tbZ@Ijh~hRELdOBBp"
      },
      "mass": 151.2258752025074,
      "monoisotopicMass": 151.11229010302,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Aib": {
      "name": "alpha-Aminoisobutyric acid diradical",
      "mf": "C4H7NO",
      "kind": "",
      "ocl": {
        "value": "dazHPBPOGgEInfZj@@",
        "coordinates": "!Bb@I~@Ha}b@K|uwwWbGt"
      },
      "mass": 85.10463700109551,
      "monoisotopicMass": 85.05276384961,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Ala": {
      "name": "Alanine diradical",
      "mf": "C3H5NO",
      "kind": "aa",
      "oneLetter": "A",
      "alternativeOneLetter": "α",
      "ocl": {
        "value": "gNyDBaxmqR[fZjZ@",
        "coordinates": "!Bb@I~@Hb}b@I~Oxa}"
      },
      "mass": 71.07801959624871,
      "monoisotopicMass": 71.03711378515,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 3
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Arg": {
      "name": "Arginine diradical",
      "mf": "C6H12N4O",
      "kind": "aa",
      "oneLetter": "R",
      "alternativeOneLetter": "ρ",
      "ocl": {
        "value": "dkLhPBgSPOEgEInWUijjihr@@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}b@I~@Ha}"
      },
      "mass": 156.18592219918227,
      "monoisotopicMass": 156.10111102405,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 4
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Argp": {
      "name": "Arginine triradical",
      "mf": "C6H11N4O",
      "kind": "",
      "ocl": {
        "value": "dglhpHpil@gWDEI[UYZfjji`T@",
        "coordinates": "!BbGvHGx@bGvH@ha}bOrH_Wxb@KW_Wx@bGt"
      },
      "mass": 155.1779814451265,
      "monoisotopicMass": 155.09328599182,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 4
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Asn": {
      "name": "Asparagine diradical",
      "mf": "C4H6N2O2",
      "kind": "aa",
      "oneLetter": "N",
      "alternativeOneLetter": "η",
      "ocl": {
        "value": "deeDPBeACqYqR[ezZjZL`@",
        "coordinates": "!BbGu~Ox`B_`BH_X`Bb@I~@Ha}"
      },
      "mass": 114.10280438280381,
      "monoisotopicMass": 114.04292744137999,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Asnp": {
      "name": "Asparagine triradical",
      "mf": "C4H5N2O2",
      "kind": "",
      "ocl": {
        "value": "dmUDpH[E@IEqgqRVvVijjXi@@",
        "coordinates": "!Bb@JH_Wxb@JH_Wxb@KW_Wx@bGt"
      },
      "mass": 113.09486362874803,
      "monoisotopicMass": 113.03510240915,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Asp": {
      "name": "Aspartic acid diradical",
      "mf": "C4H5NO3",
      "kind": "aa",
      "oneLetter": "D",
      "alternativeOneLetter": "δ",
      "ocl": {
        "value": "defLPBPYCqYqR[ezZjZL`@",
        "coordinates": "!BbGu~Ox`B_`BH_X`Bb@I~@Ha}"
      },
      "mass": 115.08756534162052,
      "monoisotopicMass": 115.02694302429,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Aspp": {
      "name": "Aspartic acid triradical",
      "mf": "C4H4NO3",
      "kind": "",
      "ocl": {
        "value": "dmVLpFcE@IEqgqRVvVijjXi@@",
        "coordinates": "!Bb@JH_Wxb@JH_Wxb@KW_Wx@bGt"
      },
      "mass": 114.07962458756472,
      "monoisotopicMass": 114.01911799206,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 4
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Asu": {
      "name": "alpha-Aminosuberic acid diradical",
      "mf": "C8H13NO3",
      "kind": "",
      "ocl": {
        "value": "dgnLPBP{CqYqR[euVfjjihr@@",
        "coordinates": "!BbGu~Ox`B_`BH_Xc|bOrH_X`BbGvHGx@bGt"
      },
      "mass": 171.19403496100773,
      "monoisotopicMass": 171.08954328213002,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Asup": {
      "name": "alpha-Aminosuberic acid triradical",
      "mf": "C8H12NO3",
      "kind": "",
      "ocl": {
        "value": "do^LpEcG@IMqoqRVuUejZjjibT@",
        "coordinates": "!BbOrH_Wxb@JH_Xc|bGvHHa}_c~H@m]}_`BH_P"
      },
      "mass": 170.18609420695194,
      "monoisotopicMass": 170.0817182499,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Boc": {
      "name": "t-Butoxycarbonyl",
      "mf": "C5H9O2",
      "kind": "",
      "ocl": {
        "value": "daxD`DpEeImjZj@@",
        "coordinates": "!B|Ou~_A||Ow}mC}_O@"
      },
      "mass": 101.12395611881479,
      "monoisotopicMass": 101.06025452921,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Bom": {
      "name": "Benzyloxymethyl",
      "mf": "C8H9O",
      "kind": "",
      "ocl": {
        "value": "deTH`DAYRUYTYj`@@@",
        "coordinates": "!B|Gsp__A||Owp_Gy|Gwp_Wy"
      },
      "mass": 121.15675888470227,
      "monoisotopicMass": 121.06533990964,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Brz": {
      "name": "2-Bromobenzyloxycarbonyl",
      "mf": "C8H6BrO2",
      "kind": "",
      "ocl": {
        "value": "dcLDPDpEd\\QImYgWYjB@@@",
        "coordinates": "!Bb@I~@Hb}b@JH_X`B_c}~@Hb}bGu~Op"
      },
      "mass": 214.03586932736317,
      "monoisotopicMass": 212.95511703252,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "Br",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Bu": {
      "name": "Butyl",
      "mf": "C4H9",
      "kind": "",
      "ocl": {
        "value": "gJPH@liJuP@",
        "coordinates": "!B@Fp@XpAl@FL"
      },
      "mass": 57.114410373442986,
      "monoisotopicMass": 57.07042529007,
      "unsaturation": -1,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 9
      }]
    },
    "Bum": {
      "name": "t-Butoxymethyl",
      "mf": "C5H11O",
      "kind": "",
      "ocl": {
        "value": "gNqHDEeIVjj`@",
        "coordinates": "!B@FL@[@AcXs|@Xvp@"
      },
      "mass": 87.14043270260808,
      "monoisotopicMass": 87.08098997409999,
      "unsaturation": -1,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Bz": {
      "name": "Benzoyl",
      "mf": "C7H5O",
      "kind": "",
      "ocl": {
        "value": "didH`DAYR[e^FX@@@@",
        "coordinates": "!BbOq~@Ha}b@I~Oxa}bGu~Op"
      },
      "mass": 105.1142599717439,
      "monoisotopicMass": 105.03403978072,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Bzl": {
      "name": "Benzyl",
      "mf": "C7H7",
      "kind": "",
      "ocl": {
        "value": "daD@`@VTeeVz`@@@",
        "coordinates": "!B|Gsp_A|_gp_A}_g|"
      },
      "mass": 91.13073655553718,
      "monoisotopicMass": 91.05477522561,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 7
      }]
    },
    "Bn": {
      "name": "Benzyl",
      "mf": "C7H7",
      "kind": "",
      "ocl": {
        "value": "daD@`@VTeeVz`@@@",
        "coordinates": "!B|Gsp_A|_gp_A}_g|"
      },
      "mass": 91.13073655553718,
      "monoisotopicMass": 91.05477522561,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 7
      }]
    },
    "Bzlo": {
      "name": "Benzyloxy",
      "mf": "C7H7O",
      "kind": "",
      "ocl": {
        "value": "didH`HAYRUe^Fh@@@@",
        "coordinates": "!B|Gwp_OC}|Gq~_A}|Gu~_p"
      },
      "mass": 107.13014147985547,
      "monoisotopicMass": 107.04968984518,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Cha": {
      "name": "beta-Cyclohexylalanine diradical",
      "mf": "C9H15NO",
      "kind": "",
      "ocl": {
        "value": "dknHPBPOEgEInWe]NZjjjcH@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvH@gxbGvH_Wx"
      },
      "mass": 153.22184251721796,
      "monoisotopicMass": 153.11536410745,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Chxo": {
      "name": "Cyclohexyloxy",
      "mf": "C6H11O",
      "kind": "",
      "ocl": {
        "value": "daDH`HAYRVU[jjj@@",
        "coordinates": "!B|Gsp_A|_gp_A}_g|"
      },
      "mass": 99.15116859934332,
      "monoisotopicMass": 99.08098997409999,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Cit": {
      "name": "Citrulline diradical",
      "mf": "C6H11N3O2",
      "kind": "",
      "ocl": {
        "value": "dkODPBdttOEgEInWUijjihr@@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}b@I~@Ha}"
      },
      "mass": 157.170683157999,
      "monoisotopicMass": 157.08512660696,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Citp": {
      "name": "Citrulline triradical",
      "mf": "C6H10N3O2",
      "kind": "",
      "ocl": {
        "value": "dgoDpHJ\\l@gWDEI[UYZfjji`T@",
        "coordinates": "!BbGvHGx@bGvH@ha}bOrH_Wxb@KW_Wx@bGt"
      },
      "mass": 156.16274240394318,
      "monoisotopicMass": 156.07730157473,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 10
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Clz": {
      "name": "2-Chlorobenzyloxycarbonyl",
      "mf": "C8H6ClO2",
      "kind": "",
      "ocl": {
        "value": "dcLDPDpEdXaImYgWYjB@@@",
        "coordinates": "!Bb@I~@Hb}b@JH_X`B_c}~@Hb}bGu~Op"
      },
      "mass": 169.58527912946118,
      "monoisotopicMass": 169.00563211451998,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "Cl",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Cp": {
      "name": "Cyclopentadienyl",
      "mf": "C5H5",
      "kind": "",
      "ocl": {
        "value": "gFpH@liLimRp@",
        "coordinates": "!B\\OtPThyEGl@fP"
      },
      "mass": 65.09338325395512,
      "monoisotopicMass": 65.03912516115,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 5
      }]
    },
    "Cys": {
      "name": "Cysteine diradical",
      "mf": "C3H5NOS",
      "kind": "aa",
      "oneLetter": "C",
      "alternativeOneLetter": "ς",
      "ocl": {
        "value": "dazHpBPOEgG`aInVZjcH@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGt"
      },
      "mass": 103.14280700237578,
      "monoisotopicMass": 103.00918495955,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 3
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Cysp": {
      "name": "Cysteine triradical",
      "mf": "C3H4NOS",
      "kind": "",
      "ocl": {
        "value": "diFHHBD@f@agGoEIVVjjfLP@",
        "coordinates": "!BbGvHHa}_c~HM]}_`BH_P"
      },
      "mass": 102.13486624831998,
      "monoisotopicMass": 102.00135992732,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 3
      }, {
        "symbol": "H",
        "number": 4
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "D": {
      "name": "Deuterium",
      "mf": "[2H]",
      "kind": "",
      "ocl": {
        "value": "eFAAYhBLCEH@",
        "coordinates": "!B@FL"
      },
      "mass": 2.01410177812,
      "monoisotopicMass": 2.01410177812,
      "unsaturation": -1,
      "elements": [{
        "symbol": "H",
        "number": 1,
        "isotope": 2
      }]
    },
    "Dde": {
      "name": "Dde",
      "mf": "C10H13O2",
      "kind": "",
      "ocl": {
        "value": "dklD`FDEgHhihicIVZfZj@@",
        "coordinates": "!Bb@I~@Ha}upJH@m]}_`BH_Wx@b@I}bOrH"
      },
      "mass": 165.20939861871415,
      "monoisotopicMass": 165.09155465812998,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Dnp": {
      "name": "2,4-Dinitrophenyl",
      "mf": "C6H3N2O4",
      "kind": "",
      "ocl": {
        "value": "dkmB`bWatpVRd^VS{HhheEUFfBAbX@@",
        "coordinates": "!B_c~H_]]}b@I~Owx_`BH_]]}_c~H_]]}"
      },
      "mass": 167.09926376274353,
      "monoisotopicMass": 167.00928158383,
      "unsaturation": 11,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 3
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 4
      }]
    },
    "Et": {
      "name": "Ethyl",
      "mf": "C2H5",
      "kind": "",
      "ocl": {
        "value": "eMBAYRZ@",
        "coordinates": "!B@Fp@Xp"
      },
      "mass": 29.061175563749384,
      "monoisotopicMass": 29.03912516115,
      "unsaturation": -1,
      "elements": [{
        "symbol": "C",
        "number": 2
      }, {
        "symbol": "H",
        "number": 5
      }]
    },
    "Fmoc": {
      "name": "Fluorenylmethoxycarbonyl",
      "mf": "C15H11O2",
      "kind": "",
      "ocl": {
        "value": "fde@b@DX@liMkLrjxeVCzLuT@@@P@@@",
        "coordinates": "!BbOq~@Ha}bOrH_]ARcm}Tv~i`pAeKv|@fpB[j[~iozfAKvp"
      },
      "mass": 223.24719659427882,
      "monoisotopicMass": 223.07590459367,
      "unsaturation": 19,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "For": {
      "name": "Formyl",
      "mf": "CHO",
      "kind": "",
      "ocl": {
        "value": "eMJDVTfP@",
        "coordinates": "!B@Fp@Xp"
      },
      "mass": 29.018081575109303,
      "monoisotopicMass": 29.0027396518,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 1
      }, {
        "symbol": "H",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Gln": {
      "name": "Glutamine diradical",
      "mf": "C5H8N2O2",
      "kind": "aa",
      "oneLetter": "Q",
      "alternativeOneLetter": "ξ",
      "ocl": {
        "value": "dmUDPBUICqYqR[evfjihr@@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHGx@bGt"
      },
      "mass": 128.12942178765059,
      "monoisotopicMass": 128.05857750584,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 8
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Glnp": {
      "name": "Glutamine triradical",
      "mf": "C5H7N2O2",
      "kind": "",
      "ocl": {
        "value": "dcuDpH{MAYeqWqRVuejZjiad@",
        "coordinates": "!BbGvHGx@bGvH@ha}_c~HM]}_`BH_P"
      },
      "mass": 127.12148103359483,
      "monoisotopicMass": 127.05075247361,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Glp": {
      "name": "Pyroglutamine",
      "mf": "C5H5NO2",
      "kind": "",
      "ocl": {
        "value": "deVDPBRP|V\\TfygxYjjZL`@",
        "coordinates": "!Bb@I~@Ha}tEJNwr[@UMo@FXBN"
      },
      "mass": 111.09889631403748,
      "monoisotopicMass": 111.03202840472,
      "unsaturation": 6,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Glu": {
      "name": "Glutamic acid diradical",
      "mf": "C5H7NO3",
      "kind": "aa",
      "oneLetter": "E",
      "alternativeOneLetter": "ε",
      "ocl": {
        "value": "dmVLPBRUCqYqR[evfjihr@@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHGx@bGt"
      },
      "mass": 129.11418274646732,
      "monoisotopicMass": 129.04259308875,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Glup": {
      "name": "Glutamic acid triradical",
      "mf": "C5H6NO3",
      "kind": "",
      "ocl": {
        "value": "dcvLpNcM@IeqWqRVuejZjiad@",
        "coordinates": "!BbGvHGx@bGvH@ha}_c~HM]}_`BH_P"
      },
      "mass": 128.10624199241153,
      "monoisotopicMass": 128.03476805652002,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Gly": {
      "name": "Glycine diradical",
      "mf": "C2H3NO",
      "kind": "aa",
      "oneLetter": "G",
      "alternativeOneLetter": "γ",
      "ocl": {
        "value": "gGYDBaxuqR[Yj@@",
        "coordinates": "!BbOq~@Ha}bOrH_P"
      },
      "mass": 57.051402191401905,
      "monoisotopicMass": 57.021463720689994,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 2
      }, {
        "symbol": "H",
        "number": 3
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Hci": {
      "name": "Homocitrulline diradical",
      "mf": "C7H13N3O2",
      "kind": "",
      "ocl": {
        "value": "dgoDPBVtLOEgEInWUZZjjfcH@",
        "coordinates": "!BbGu~Ox`B_`BH_Xc|bOrH_X`BbGvHGx@bGt"
      },
      "mass": 171.19730056284578,
      "monoisotopicMass": 171.10077667142,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Hcip": {
      "name": "Homocitrulline triradical",
      "mf": "C7H12N3O2",
      "kind": "",
      "ocl": {
        "value": "do_DpHI\\\\EdwFEI[UVVijjjfIP@",
        "coordinates": "!BbOrH_Wxb@JH_Xc|bGvHHa}_c~H@m]}_`BH_P"
      },
      "mass": 170.18935980879002,
      "monoisotopicMass": 170.09295163918998,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "His": {
      "name": "Histidine diradical",
      "mf": "C6H7N3O",
      "kind": "aa",
      "oneLetter": "H",
      "alternativeOneLetter": "ζ",
      "ocl": {
        "value": "dcOHPBGTCqYqR[eyUvZjejL`@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGwPTh{_UMo@FP"
      },
      "mass": 137.13951521745759,
      "monoisotopicMass": 137.05891185847,
      "unsaturation": 8,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Hisp": {
      "name": "Histidine triradical",
      "mf": "C6H6N3O",
      "kind": "",
      "ocl": {
        "value": "dkoHpHHSAYUqwqRY]YXjjVjihy@@",
        "coordinates": "!BTmA}bL@fUHRN`H`BbGu~Ox`Buwu~@Ha}"
      },
      "mass": 136.13157446340182,
      "monoisotopicMass": 136.05108682624,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Hser": {
      "name": "Homoserine diradical",
      "mf": "C4H7NO2",
      "kind": "",
      "ocl": {
        "value": "diFDPBPP|V\\Tfy^Zjhr@@",
        "coordinates": "!BbGu~Ox`B_`BH_X`Bb@JH_P"
      },
      "mass": 101.10404192541378,
      "monoisotopicMass": 101.04767846918,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Hserp": {
      "name": "Homoserine triradical",
      "mf": "C4H6NO2",
      "kind": "",
      "ocl": {
        "value": "defDpJbPV^\\Q|TeVVjji`d@",
        "coordinates": "!Bb@JH_X`BbGu~Oxc|uwu~@Ha}"
      },
      "mass": 100.09610117135801,
      "monoisotopicMass": 100.03985343695001,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Hyp": {
      "name": "Hydroxyproline diradical",
      "mf": "C5H7NO2",
      "kind": "",
      "ocl": {
        "value": "deVDPBRP|V\\\\bfbbOCMUUIdE@@",
        "coordinates": "!Bb@I~@Ha}tEJNwr[@UMo@FUJO"
      },
      "mass": 113.11477782214904,
      "monoisotopicMass": 113.04767846918,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Hypp": {
      "name": "Hydroxyproline triradical",
      "mf": "C5H6NO2",
      "kind": "",
      "ocl": {
        "value": "dmvDpJaPB^\\Y|TeeWjZjjidRL`@",
        "coordinates": "!BBOpH_UARcc}TNtBY@HyRSpCQDr\\"
      },
      "mass": 112.10683706809326,
      "monoisotopicMass": 112.03985343695001,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Ile": {
      "name": "Isoleucine diradical",
      "mf": "C6H11NO",
      "kind": "aa",
      "oneLetter": "I",
      "alternativeOneLetter": "ι",
      "ocl": {
        "value": "defHPBPOEgEInVyjjdrT`@",
        "coordinates": "!BbGu~Oxc|_`BH_Xc|b@I~Oxa}"
      },
      "mass": 113.15787181078912,
      "monoisotopicMass": 113.08406397853,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Ivdde": {
      "name": "1-[4,4-dimethyl-2,6-dioxocyclohexylidene)-3-methylbutyl",
      "mf": "C13H19O2",
      "kind": "",
      "ocl": {
        "value": "f`a@b@NR@lyEEDhhigEVfjYjj`@@",
        "coordinates": "!BbOq~@Ha}urHGxuwu~@Ha}_`CW_Xa}bOq}b@JH"
      },
      "mass": 207.28925083325453,
      "monoisotopicMass": 207.13850485151,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 19
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Leu": {
      "name": "Leucine diradical",
      "mf": "C6H11NO",
      "kind": "aa",
      "oneLetter": "L",
      "alternativeOneLetter": "λ",
      "ocl": {
        "value": "defHPBPOEgEInWijjhr@@",
        "coordinates": "!BbGu~Ox`B_`BH_X`Bb@I~@Ha}"
      },
      "mass": 113.15787181078912,
      "monoisotopicMass": 113.08406397853,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Lys": {
      "name": "Lysine diradical",
      "mf": "C6H12N2O",
      "kind": "aa",
      "oneLetter": "K",
      "alternativeOneLetter": "κ",
      "ocl": {
        "value": "dmUHPBU@|V\\Tfy]YjjjL`@",
        "coordinates": "!BbGu~Ox`B_`BHoX`Bb@JH_X`BbKt"
      },
      "mass": 128.17251577629068,
      "monoisotopicMass": 128.09496301519,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Lysp": {
      "name": "Lysine triradical",
      "mf": "C6H11N2O",
      "kind": "",
      "ocl": {
        "value": "dcuHpH{PVY\\U|TeUYZjjjXY@@",
        "coordinates": "!Bb@JH_X`BbGvH@ha}_c~H@m]}_`BH_P"
      },
      "mass": 127.16457502223491,
      "monoisotopicMass": 127.08713798295999,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Mbh": {
      "name": "4,4'-Dimethoxybenzhydryl",
      "mf": "C15H15O2",
      "kind": "",
      "ocl": {
        "value": "fdy@b@G^@liLsJkzlcZmT@@@UP@@@",
        "coordinates": "!BbGvHGx_`BH_Xa}uwvHHc|_c}~Oxa}uwvHGxbGwW_P"
      },
      "mass": 227.27895961050194,
      "monoisotopicMass": 227.10720472258998,
      "unsaturation": 15,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Me": {
      "name": "Methyl",
      "mf": "CH3",
      "kind": "",
      "ocl": {
        "value": "eFBAYc@@",
        "coordinates": "!B@FL"
      },
      "mass": 15.03455815890258,
      "monoisotopicMass": 15.02347509669,
      "unsaturation": -1,
      "elements": [{
        "symbol": "C",
        "number": 1
      }, {
        "symbol": "H",
        "number": 3
      }]
    },
    "Mebzl": {
      "name": "4-Methylbenzyl",
      "mf": "C8H9",
      "kind": "",
      "ocl": {
        "value": "did@`@VTee]nh@H@@",
        "coordinates": "!B|Gsp__A|_gp_C}_gp_P"
      },
      "mass": 105.15735396038399,
      "monoisotopicMass": 105.07042529007,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 9
      }]
    },
    "Meobzl": {
      "name": "4-Methoxybenzyl",
      "mf": "C8H9O",
      "kind": "",
      "ocl": {
        "value": "deTH`AAYRVUunh@J@@",
        "coordinates": "!B|Gsp__A|_gp_A}_gp_Wy"
      },
      "mass": 121.15675888470227,
      "monoisotopicMass": 121.06533990964,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Met": {
      "name": "Methionine diradical",
      "mf": "C5H9NOS",
      "kind": "aa",
      "oneLetter": "M",
      "alternativeOneLetter": "μ",
      "ocl": {
        "value": "defHpBPOEgDPaInWYjjhr@@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}"
      },
      "mass": 131.19604181206938,
      "monoisotopicMass": 131.04048508847,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mmt": {
      "name": "4-Methoxytrityl",
      "mf": "C20H17O",
      "kind": "",
      "ocl": {
        "value": "ffcAB@B`V\\bdTTTRRRVvIhnRGMT@@@@AP@@@",
        "coordinates": "!BbKvHM^}_c}~@Hb}dXWHb}j|nHHc|AqOWoWxJV^Ho]\\BuwvHHb}"
      },
      "mass": 273.3491156779715,
      "monoisotopicMass": 273.12794016748,
      "unsaturation": 23,
      "elements": [{
        "symbol": "C",
        "number": 20
      }, {
        "symbol": "H",
        "number": 17
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Mtc": {
      "name": "2,2,5,7,8-pentamethylchroman-6-sulphonyl",
      "mf": "C14H19O3S",
      "kind": "",
      "ocl": {
        "value": "fleAa@DX\\AY`DYEHXhhilmiKW`rpDQUUD@@",
        "coordinates": "!BbGtBbGwWbGvHGxbGu~@Ha}uwu~Ox`B_c~H_Xa}b@H@_osW"
      },
      "mass": 267.36417906043516,
      "monoisotopicMass": 267.10549064548,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 14
      }, {
        "symbol": "H",
        "number": 19
      }, {
        "symbol": "O",
        "number": 3
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mtr": {
      "name": "4-Methoxy-2,3,6-trimethylbenzenesulphonyl",
      "mf": "C10H13O3S",
      "kind": "",
      "ocl": {
        "value": "do|LPDrpVXBLbdLTTTngYXBHj@@",
        "coordinates": "!BbOq}b@KWb@I~@Ha}bOsWHc|_c~H_Wx@b@JH_P"
      },
      "mass": 213.27359094915948,
      "monoisotopicMass": 213.05854045209998,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "O",
        "number": 3
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mts": {
      "name": "Mesitylene-2-sulphonyl",
      "mf": "C9H11O2S",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 183.24756861999438,
      "monoisotopicMass": 183.04797576807,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "O",
        "number": 2
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mtt": {
      "name": "4-Methyltrityl",
      "mf": "C20H17",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 257.3497107536532,
      "monoisotopicMass": 257.13302554791,
      "unsaturation": 23,
      "elements": [{
        "symbol": "C",
        "number": 20
      }, {
        "symbol": "H",
        "number": 17
      }]
    },
    "Nle": {
      "name": "Norleucine diradical",
      "mf": "C6H11NO",
      "kind": "",
      "ocl": {
        "value": "defHPBPOEgEInWYjjhr@@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}"
      },
      "mass": 113.15787181078912,
      "monoisotopicMass": 113.08406397853,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Npys": {
      "name": "3-Nitro-2-pyridinesulphenyl",
      "mf": "C5H3N2O2S",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 155.1545054234988,
      "monoisotopicMass": 154.99152351908998,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 3
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 2
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Nva": {
      "name": "Norvaline diradical",
      "mf": "C5H9NO",
      "kind": "",
      "ocl": {
        "value": "diFHPBPOEgEInWfjjL`@",
        "coordinates": "!BbGu~Ox`B_`BH_X`Bb@JH_P"
      },
      "mass": 99.13125440594231,
      "monoisotopicMass": 99.06841391407,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Odmab": {
      "name": "Odmab",
      "mf": "C20H26NO3",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 328.4260955245558,
      "monoisotopicMass": 328.19126870111995,
      "unsaturation": 15,
      "elements": [{
        "symbol": "C",
        "number": 20
      }, {
        "symbol": "H",
        "number": 26
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Orn": {
      "name": "Ornithine diradical",
      "mf": "C5H10N2O",
      "kind": "",
      "ocl": {
        "value": "deeHPBe@|V\\Tfy]fjjcH@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}"
      },
      "mass": 114.14589837144388,
      "monoisotopicMass": 114.07931295072999,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 10
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Ornp": {
      "name": "Ornithine triradical",
      "mf": "C5H9N2O",
      "kind": "",
      "ocl": {
        "value": "dmUHpHYPBQ\\Y|TeUejjjfJP@",
        "coordinates": "!BbGvHHa}b@JH_Wxb@KW_Wx@bGt"
      },
      "mass": 113.13795761738811,
      "monoisotopicMass": 113.0714879185,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Pbf": {
      "name": "2,2,4,6,7-pentamethyldihydrobenzofurane-5-sulfonyl",
      "mf": "C13H17O3S",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 253.33756165558833,
      "monoisotopicMass": 253.08984058101998,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 17
      }, {
        "symbol": "O",
        "number": 3
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Pen": {
      "name": "Penicillamine diradical",
      "mf": "C5H9NOS",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 131.19604181206938,
      "monoisotopicMass": 131.04048508847,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Penp": {
      "name": "Penicillamine triradical",
      "mf": "C5H8NOS",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 130.1881010580136,
      "monoisotopicMass": 130.03266005624,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 8
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Ph": {
      "name": "Phenyl",
      "mf": "C6H5",
      "kind": "",
      "ocl": {
        "value": "gOpH@liLkW@@@@",
        "coordinates": "!B|Owp_Gy|OwpWy"
      },
      "mass": 77.10411915069038,
      "monoisotopicMass": 77.03912516115,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 5
      }]
    },
    "Phe": {
      "name": "Phenylalanine diradical",
      "mf": "C9H9NO",
      "kind": "aa",
      "oneLetter": "F",
      "alternativeOneLetter": "φ",
      "ocl": {
        "value": "dknHPBPOEgEInWe]NZj@@cH@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvH@gxbGvH_Wx"
      },
      "mass": 147.1741979928833,
      "monoisotopicMass": 147.06841391407002,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Phepcl": {
      "name": "4-Chlorophenylalanine diradical",
      "mf": "C9H8ClNO",
      "kind": "",
      "ocl": {
        "value": "dg^HpBPOEgFxaInWe_Sfj`@bL`@",
        "coordinates": "!BbOq~@Ha}_c~H@m]}bGvH@gxbGvH_WxbGt"
      },
      "mass": 181.6191948214355,
      "monoisotopicMass": 181.02944156384,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 8
      }, {
        "symbol": "Cl",
        "number": 1
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Phg": {
      "name": "Phenylglycine",
      "mf": "C8H7NO",
      "kind": "",
      "ocl": {
        "value": "dcNHPBPOEgEInVuWYj`@Hr@@",
        "coordinates": "!BbOq~@Ha}b@I~Oxa}bGwW_Wx_cW_P"
      },
      "mass": 133.1475805880365,
      "monoisotopicMass": 133.05276384961002,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Pmc": {
      "name": "2,2,5,7,8-Pentamethylchroman-6-sulphonyl",
      "mf": "C14H19O3S",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 267.36417906043516,
      "monoisotopicMass": 267.10549064548,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 14
      }, {
        "symbol": "H",
        "number": 19
      }, {
        "symbol": "O",
        "number": 3
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Pro": {
      "name": "Proline diradical",
      "mf": "C5H7NO",
      "kind": "aa",
      "oneLetter": "P",
      "alternativeOneLetter": "π",
      "ocl": {
        "value": "difHPBPOEgEInYxYjjhr@@",
        "coordinates": "!Bb@I~@Ha}tEJNwr[@UMo@FP"
      },
      "mass": 97.11537289783075,
      "monoisotopicMass": 97.05276384961,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Pyr": {
      "name": "Pyroglutamine",
      "mf": "C5H5NO2",
      "kind": "",
      "ocl": {
        "value": "deVDPBRP|V\\TfygxYjjZL`@",
        "coordinates": "!Bb@I~@Ha}tEJNwr[@UMo@FXBN"
      },
      "mass": 111.09889631403748,
      "monoisotopicMass": 111.03202840472,
      "unsaturation": 6,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Sar": {
      "name": "Sarcosine diradical",
      "mf": "C3H5NO",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 71.07801959624871,
      "monoisotopicMass": 71.03711378515,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 3
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Ser": {
      "name": "Serine diradical",
      "mf": "C3H5NO2",
      "kind": "aa",
      "oneLetter": "S",
      "alternativeOneLetter": "σ",
      "ocl": {
        "value": "dazDPBS`|V\\TfyYjjL`@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}bGt"
      },
      "mass": 87.07742452056698,
      "monoisotopicMass": 87.03202840472,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 3
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Serp": {
      "name": "Serine triradical",
      "mf": "C3H4NO2",
      "kind": "",
      "ocl": {
        "value": "diFDpB`PBV\\^|TeYZjjXq@@",
        "coordinates": "!BbGvHHa}_c~HM]}_`BH_P"
      },
      "mass": 86.06948376651121,
      "monoisotopicMass": 86.02420337249,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 3
      }, {
        "symbol": "H",
        "number": 4
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Sta": {
      "name": "Statine diradical",
      "mf": "C8H15NO2",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 157.210511544801,
      "monoisotopicMass": 157.11027872702002,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Stap": {
      "name": "Statine triradical",
      "mf": "C8H14NO2",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 156.2025707907452,
      "monoisotopicMass": 156.10245369479,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Tacm": {
      "name": "Trimethylacetamidomethyl",
      "mf": "C6H12NO",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 114.16581256484488,
      "monoisotopicMass": 114.09188901076,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Tbdms": {
      "name": "t-Butyldimethylsilyl",
      "mf": "C6H15Si",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 115.2690253969541,
      "monoisotopicMass": 115.09430201810001,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "Si",
        "number": 1
      }]
    },
    "Tbu": {
      "name": "t-Butyl",
      "mf": "C4H9",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 57.114410373442986,
      "monoisotopicMass": 57.07042529007,
      "unsaturation": -1,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 9
      }]
    },
    "Tbuo": {
      "name": "t-Butoxy",
      "mf": "C4H9O",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 73.11381529776126,
      "monoisotopicMass": 73.06533990964,
      "unsaturation": -1,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Tbuthio": {
      "name": "t-Butylthio",
      "mf": "C4H9S",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 89.17919777957005,
      "monoisotopicMass": 89.04249646446999,
      "unsaturation": -1,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Tfa": {
      "name": "Trifluoroacetyl",
      "mf": "C2F3O",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 97.01608620597878,
      "monoisotopicMass": 96.99012410776,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 2
      }, {
        "symbol": "F",
        "number": 3
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Thr": {
      "name": "Threonine diradical",
      "mf": "C4H7NO2",
      "kind": "aa",
      "oneLetter": "T",
      "alternativeOneLetter": "τ",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 101.10404192541378,
      "monoisotopicMass": 101.04767846918,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Thrp": {
      "name": "Threonine triradical",
      "mf": "C4H6NO2",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 100.09610117135801,
      "monoisotopicMass": 100.03985343695001,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 4
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Tfsi": {
      "name": "(Bis)(trifluoromethanesulfonyl)imide",
      "mf": "C2F6NO4S2",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 280.1457884908235,
      "monoisotopicMass": 279.91729380789,
      "unsaturation": -1,
      "elements": [{
        "symbol": "C",
        "number": 2
      }, {
        "symbol": "F",
        "number": 6
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 4
      }, {
        "symbol": "S",
        "number": 2
      }]
    },
    "Tips": {
      "name": "Triisopropylsilyl",
      "mf": "C9H21Si",
      "kind": "",
      "ocl": {
        "value": "dmT@P@VX\\DffYjjjh@@",
        "coordinates": "!B_a@gHb\\]FBIuWxP^zi~KwxPFAt"
      },
      "mass": 157.34887761149452,
      "monoisotopicMass": 157.14125221148,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 21
      }, {
        "symbol": "Si",
        "number": 1
      }]
    },
    "Tms": {
      "name": "Trimethylsilyl",
      "mf": "C3H9Si",
      "kind": "",
      "ocl": {
        "value": "gJPD@lqpRZj`@",
        "coordinates": "!BbOq~@GxbGt"
      },
      "mass": 73.1891731824137,
      "monoisotopicMass": 73.04735182472,
      "unsaturation": 1,
      "elements": [{
        "symbol": "C",
        "number": 3
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "Si",
        "number": 1
      }]
    },
    "Tos": {
      "name": "Tosyl",
      "mf": "C7H7O2S",
      "kind": "",
      "ocl": {
        "value": "dmtDPDpEf@cHiCDeafV@B@@",
        "coordinates": "!B|Ou||Ovw|Gwp_Gy|GwpWy|Gt"
      },
      "mass": 155.1943338103008,
      "monoisotopicMass": 155.01667563914998,
      "unsaturation": 7,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "O",
        "number": 2
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Trp": {
      "name": "Tryptophan diradical",
      "mf": "C11H10N2O",
      "kind": "aa",
      "oneLetter": "W",
      "alternativeOneLetter": "ω",
      "ocl": {
        "value": "f`qQA@BFPCqXxiMr|rnhsoSUTa@QCD@@",
        "coordinates": "!BbOq~@Ha}_c~H@m]}bGwPTh{_UMojXL@YpB[@Ini`"
      },
      "mass": 186.21031375185538,
      "monoisotopicMass": 186.07931295073,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 10
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Trpp": {
      "name": "Tryptophan triradical",
      "mf": "C11H9N2O",
      "kind": "",
      "ocl": {
        "value": "fhiQC@HFB@I\\x~|TfYU_ebLDjhDHjibFd@",
        "coordinates": "!BTmA}bL@fUHR_Ihz@iVBeXHc|grZH_WxbOsW_Wx@bGt"
      },
      "mass": 185.20237299779959,
      "monoisotopicMass": 185.07148791850003,
      "unsaturation": 15,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Trt": {
      "name": "Trityl",
      "mf": "C19H15",
      "kind": "",
      "ocl": {
        "value": "fbm@B@@KJSSLrjkyhnRGMT@@@@@@@@",
        "coordinates": "!BrHI~PGy_rMvW@l`BQCvWw\\bBAg}~PGy@]i}~W|c]cNwH`i_]_e|"
      },
      "mass": 243.32309334880637,
      "monoisotopicMass": 243.11737548345,
      "unsaturation": 23,
      "elements": [{
        "symbol": "C",
        "number": 19
      }, {
        "symbol": "H",
        "number": 15
      }]
    },
    "Tyr": {
      "name": "Tyrosine diradical",
      "mf": "C9H9NO2",
      "kind": "aa",
      "oneLetter": "Y",
      "alternativeOneLetter": "ψ",
      "ocl": {
        "value": "dg^DPBRp|V\\Tfy^U}NZj@BHr@@",
        "coordinates": "!BbOq~@Ha}_c~H@m]}bGvH@gxbGvH_WxbGt"
      },
      "mass": 163.1736029172016,
      "monoisotopicMass": 163.06332853364,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Tyrp": {
      "name": "Tyrosine triradical",
      "mf": "C9H8NO2",
      "kind": "",
      "ocl": {
        "value": "do~DpEapBS\\[|Tee]YYnh@JjdbT@",
        "coordinates": "!B_`BHGx@bGvH@h`BbKvH@ha}_c~H@m]}_`BHoP"
      },
      "mass": 162.16566216314578,
      "monoisotopicMass": 162.05550350141,
      "unsaturation": 11,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 8
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Val": {
      "name": "Valine",
      "mf": "C5H9NO",
      "kind": "aa",
      "oneLetter": "V",
      "alternativeOneLetter": "ν",
      "ocl": {
        "value": "diFHPBPOEgEInVfjjL`@",
        "coordinates": "!Bb@I~@Ha}_c~H@m]}_`BH_P"
      },
      "mass": 99.13125440594231,
      "monoisotopicMass": 99.06841391407,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Valoh": {
      "name": "beta-Hydroxyvaline diradical",
      "mf": "C5H9NO2",
      "kind": "",
      "ocl": {
        "value": "defDPBS`|V\\TfyZfjjcH@",
        "coordinates": "!Bb@I~@Ha}b@I~Oxa}Owy~OpA~"
      },
      "mass": 115.13065933026058,
      "monoisotopicMass": 115.06332853364,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Valohp": {
      "name": "beta-Hydroxyvaline triradical",
      "mf": "C5H8NO2",
      "kind": "",
      "ocl": {
        "value": "dmVDpFaPBQ\\Y|\\bTbaTjjjXq@@",
        "coordinates": "!BbGvHHa}_Xc|bGxb@KW_Wx@bGt"
      },
      "mass": 114.1227185762048,
      "monoisotopicMass": 114.05550350141002,
      "unsaturation": 3,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 8
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Xan": {
      "name": "Xanthyl",
      "mf": "C13H9O",
      "kind": "",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 181.21043836837848,
      "monoisotopicMass": 181.06533990964002,
      "unsaturation": 17,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Xle": {
      "name": "Leucine or Isoleucine diradical",
      "mf": "C6H11NO",
      "kind": "aa",
      "oneLetter": "J",
      "mass": 113.15787181078912,
      "monoisotopicMass": 113.08406397853,
      "unsaturation": 2,
      "elements": [{
        "symbol": "C",
        "number": 6
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 1
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Z": {
      "name": "Benzyloxycarbonyl",
      "mf": "C8H7O2",
      "kind": "",
      "ocl": {
        "value": "dmtD`DpEeImYVUfh@@@@",
        "coordinates": "!Bb@I~@Ha}b@JH_Xc|_c~H_Xa}_c|"
      },
      "mass": 135.14028230090898,
      "monoisotopicMass": 135.04460446475,
      "unsaturation": 9,
      "elements": [{
        "symbol": "C",
        "number": 8
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Damp": {
      "name": "Desoxyadenosine monophosphate diradical",
      "mf": "C10H12N5O5P",
      "kind": "DNAp",
      "oneLetter": "A",
      "alternativeOneLetter": "α",
      "ocl": {
        "value": "fnsiS@IASUlJB]xGbkplxyDhhldhiEEUeSdTekUUUULBATXPlKd@@",
        "coordinates": "!Bqc}{JxyO|XoSWC}W]poGQ\\Ou}]rmx\\Ou}]{qpza|qb}MJwlk^sFO|X"
      },
      "mass": 313.2069506932622,
      "monoisotopicMass": 313.05760550518,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 5
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dcmp": {
      "name": "Desoxycytidine monophosphate diradical",
      "mf": "C9H12N3O6P",
      "kind": "DNAp",
      "oneLetter": "C",
      "alternativeOneLetter": "ς",
      "ocl": {
        "value": "fjmps@IQKB`g^BCqUxV\\\\bTTVRTTbb^iqNZjjjifVkBEa\\`@",
        "coordinates": "!Bqc}{JxyO|XoSWA}_W]poGQ\\GuMKuMh\\Gu}]{qpSF]tWQTvatP"
      },
      "mass": 289.18221329795364,
      "monoisotopicMass": 289.04637211589,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dgmp": {
      "name": "Desoxyguanosine monophosphate diradical",
      "mf": "C10H12N5O6P",
      "kind": "DNAp",
      "oneLetter": "G",
      "alternativeOneLetter": "γ",
      "ocl": {
        "value": "fakhs@IASUlJB]{hOEWaYqrIQQYIQRJJkQTyEIZuUUUSRtsUaBpnP@",
        "coordinates": "!Bqc}{JxyO|XoSWA}W]poGQ\\Gu}]rmx\\Ou}]{qpza|qb}MJwlk^sFza|q`"
      },
      "mass": 329.20635561758047,
      "monoisotopicMass": 329.05252012475,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dtmp": {
      "name": "Desoxythymidine monophosphate diradical",
      "mf": "C10H13N2O7P",
      "kind": "DNAp",
      "oneLetter": "T",
      "alternativeOneLetter": "τ",
      "ocl": {
        "value": "ff}Qs@IQaPSoAjCqUxV\\\\bTTVRTTbbZUNIsUUUULsSVDKBy@@",
        "coordinates": "!Bqc}{JxyO|XoSWC}_W]poGQ\\GuMKuMh\\Gu}]{qpSF]tWQTvaSZGQ"
      },
      "mass": 304.1935916616171,
      "monoisotopicMass": 304.04603776326,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dump": {
      "name": "Desoxyuridine monophosphate diradical",
      "mf": "C9H11N2O7P",
      "kind": "DNAp",
      "oneLetter": "U",
      "alternativeOneLetter": "υ",
      "ocl": {
        "value": "fjmQs@IQaPSoAJCqUxV\\\\bTTVRTTbb^iqNZjjjifYkBEa\\`@",
        "coordinates": "!Bqc}{JxyO|XoSWA}_W]poGQ\\GuMKuMh\\Gu}]{qpSF]tWQTvatP"
      },
      "mass": 290.1669742567703,
      "monoisotopicMass": 290.0303876988,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Drmp": {
      "name": "Desoxyribose monophosphate diradical",
      "mf": "C5H7O5P",
      "kind": "DNAp",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 178.08005138207807,
      "monoisotopicMass": 178.00311032188,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "O",
        "number": 5
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dadp": {
      "name": "Desoxyadenosine diphosphate diradical",
      "mf": "C10H13N5O8P2",
      "kind": "DNApp",
      "oneLetter": "A",
      "ocl": {
        "value": "fmwhH`IASM\\JBl{wQ`|U^F_AkbdlsjsSOoRtyEMYuUUUM@pSEQaBpnP@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGu}utnDM^HGwWzf~_Ih}M_`AKvto[_`@_`A~grZ_I`"
      },
      "mass": 393.1868682186928,
      "monoisotopicMass": 393.02393639454,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Dcdp": {
      "name": "Desoxycytidine diphosphate diradical",
      "mf": "C9H13N3O9P2",
      "kind": "DNApp",
      "oneLetter": "C",
      "ocl": {
        "value": "fikqH`IQGB`kN|EoP^JoCOaUqrIQQYIQRJKGRJgDejjjjZYfZkBEa\\`@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFGx@Owx@_mQ"
      },
      "mass": 369.16213082338425,
      "monoisotopicMass": 369.01270300525005,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Dgdp": {
      "name": "Desoxyguanosine diphosphate diradical",
      "mf": "C10H13N5O9P2",
      "kind": "DNApp",
      "oneLetter": "G",
      "ocl": {
        "value": "fcoiH`IASM\\JBl{wQ{Axj|L~CWEIYgUff_^fZ\\bflzjjjfiZifZlHVEr@@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGu}utnD@m^H@gwWzf~_Ih}M_`AKvto[_`@_`A~gr[j[y|f"
      },
      "mass": 409.186273143011,
      "monoisotopicMass": 409.01885101411,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Dtdp": {
      "name": "Desoxythymidine diphosphate diradical",
      "mf": "C10H14N2O10P2",
      "kind": "DNApp",
      "oneLetter": "T",
      "ocl": {
        "value": "fe{Ph`IQaPUg^Ct\\p^JoCO`uqrIQQYIQRJKEJQTxdmUUUSSMTsVDKBy@@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^HMQbGuMcqLX@m^H@gwWKB__t]Q_`@SFALX_`@_`A~w}D"
      },
      "mass": 384.1735091870477,
      "monoisotopicMass": 384.01236865262,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Dudp": {
      "name": "Desoxyuridine diphosphate diradical",
      "mf": "C9H12N2O10P2",
      "kind": "DNApp",
      "oneLetter": "U",
      "ocl": {
        "value": "fikPh`IQaPUg^Bwhp^JoCOaUqrIQQYIQRJKGRJgDejjjjZYjYkBEa\\`@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFGx@Owx@_mQ"
      },
      "mass": 370.1468917822009,
      "monoisotopicMass": 369.99671858816,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Datp": {
      "name": "Desoxyadenosine triphosphate diradical",
      "mf": "C10H14N5O11P3",
      "kind": "DNAppp",
      "oneLetter": "A",
      "ocl": {
        "value": "eohZMJ@I@diehJAKGOFnakg`OESpr|Mo@yqrIQQYIQRJKYZQKVRcbIJjZjjjihFAhjZcAAXKb@@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGu}utnDM^H@gwWzf~_Ih}M_`AKvto[@hcW@`A~grZ_Igx@_`@@_c}~"
      },
      "mass": 473.16678574412344,
      "monoisotopicMass": 472.9902672839,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Dctp": {
      "name": "Desoxycytidine triphosphate diradical",
      "mf": "C9H14N3O12P3",
      "kind": "DNAppp",
      "oneLetter": "C",
      "ocl": {
        "value": "fkopZ`IQGB`kN|Fk^{NCqUxY|I~BwGHeEEdeEHhl]HlYJ\\RVjjjiifVjfkBEa\\`@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFOrHupH@_mQ_`A~@@A~Owx"
      },
      "mass": 449.14204834881485,
      "monoisotopicMass": 448.97903389461004,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 12
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Dgtp": {
      "name": "Desoxyguanosine triphosphate diradical",
      "mf": "C10H14N5O12P3",
      "kind": "DNAppp",
      "oneLetter": "G",
      "ocl": {
        "value": "e`TZCJ@I@diehJAKGOFnamgo`OESpr|CoByqrIQQYIQRJKYZQQYrT\\QIUSUUUUMRuMLtuVBBpWD@@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGu}utnD@m^H@gwWzf~_Ih}M_`AKvto[@hcW@`A~gr[j[y|f_`A~@@A~Owx"
      },
      "mass": 489.16619066844174,
      "monoisotopicMass": 488.98518190347005,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 12
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Dttp": {
      "name": "Desoxythymidine triphosphate diradical",
      "mf": "C10H15N2O13P3",
      "kind": "DNAppp",
      "oneLetter": "T",
      "ocl": {
        "value": "fgQZ`IQaPUg^BwhygnCqUxY|E~FwGHeEEdeEHhlTiDSISbRuUUUMLuMMMVDKBy@@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFALXHcW@`A~w}E~@Gx@@Gx_`"
      },
      "mass": 464.15342671247834,
      "monoisotopicMass": 463.97869954198,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 13
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Dutp": {
      "name": "Desoxyuridine triphosphate diradical",
      "mf": "C9H13N2O13P3",
      "kind": "DNAppp",
      "oneLetter": "U",
      "ocl": {
        "value": "fkoQZ`IQaPUg^CUoQ{NCqUxY|I~BwGHeEEdeEHhl]HlYJ\\RVjjjiiffffkBEa\\`@",
        "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFOrHupH@_mQ_`A~@@A~Owx"
      },
      "mass": 450.1268093076315,
      "monoisotopicMass": 449.96304947752,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 13
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Dade": {
      "name": "Desoxyadenosine diradical",
      "mf": "C10H11N5O2",
      "kind": "DNA",
      "oneLetter": "A",
      "ocl": {
        "value": "fluha@IF]ELJ@|QNJRsN|rntyYpXuUUTBATXPlKd@@",
        "coordinates": "!B\\KqpQARcg|T^|X@@Id`zeHo@Ie}]vaLcg|T^qAMDDvN_xy"
      },
      "mass": 233.22703316783156,
      "monoisotopicMass": 233.09127461582,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 2
      }]
    },
    "Dcyt": {
      "name": "Desoxycytidine diradical",
      "mf": "C9H11N3O3",
      "kind": "DNA",
      "oneLetter": "C",
      "ocl": {
        "value": "fhiqa@IVCBa`^HgEIYg^Y~gG^jjjiejpaXWH@",
        "coordinates": "!BBOpH_UARcc}TN|Y@PIe`zeIO@MDSIrpXTd}RSqLgTd|"
      },
      "mass": 209.202295772523,
      "monoisotopicMass": 209.08004122653,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Dgua": {
      "name": "Desoxyguanosine diradical",
      "mf": "C10H11N5O3",
      "kind": "DNA",
      "oneLetter": "G",
      "ocl": {
        "value": "fbmia@IF]ELJYAxb\\Tef]ye^Z\\lxLZjjjeZfkBEa\\`@",
        "coordinates": "!B\\KqpQARcg|T^|X@@Id`zeHo@Ie}]vaLcg|T^qAMDDvN_vaLcg|"
      },
      "mass": 249.22643809214986,
      "monoisotopicMass": 249.08618923539,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Dthy": {
      "name": "Desoxythymidine diradical",
      "mf": "C10H12N2O4",
      "kind": "DNA",
      "oneLetter": "T",
      "ocl": {
        "value": "fdyPQ@IVaPtP^HgEIYg^YuiqwjjjjYikBEa\\`@",
        "coordinates": "!BBOpH_UARcc}TN|Y@PIe`zeIO@MDSIrpXTd}RSqLgDr]RSp"
      },
      "mass": 224.2136741361865,
      "monoisotopicMass": 224.07970687390002,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 4
      }]
    },
    "Dura": {
      "name": "Desoxyuridine diradical",
      "mf": "C9H10N2O4",
      "kind": "DNA",
      "oneLetter": "U",
      "ocl": {
        "value": "fhiPQ@IVaPpP^HgEIYg^Y~gG^jjjifZpaXWH@",
        "coordinates": "!BBOpH_UARcc}TN|Y@PIe`zeIO@MDSIrpXTd}RSqLgTd|"
      },
      "mass": 210.1870567313397,
      "monoisotopicMass": 210.06405680944,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 10
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 4
      }]
    },
    "Amp": {
      "name": "Adenosine monophosphate diradical",
      "mf": "C10H12N5O6P",
      "kind": "RNAp",
      "oneLetter": "A",
      "alternativeOneLetter": "α",
      "ocl": {
        "value": "fakhs@INBwlJ\\TgHOFwaEqrIQQSYQJIRIMLyxMVuUUUPLpEPQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@@"
      },
      "mass": 329.20635561758047,
      "monoisotopicMass": 329.05252012475,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Cmp": {
      "name": "Cytidine monophosphate diradical",
      "mf": "C9H12N3O7P",
      "kind": "RNAp",
      "oneLetter": "C",
      "alternativeOneLetter": "ς",
      "ocl": {
        "value": "ff}qs@I^kBgENSdGc[pbxyDhhilheDiLv\\BVjjjjYfZbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
      },
      "mass": 305.1816182222719,
      "monoisotopicMass": 305.04128673546,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Gmp": {
      "name": "Guanosine monophosphate diradical",
      "mf": "C10H12N5O7P",
      "kind": "RNAp",
      "oneLetter": "G",
      "alternativeOneLetter": "γ",
      "ocl": {
        "value": "fi{is@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\SN^CUmUUUUKMSMQDSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtP@gD}D@"
      },
      "mass": 345.20576054189877,
      "monoisotopicMass": 345.04743474432,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Tmp": {
      "name": "Thymidine monophosphate diradical",
      "mf": "C10H13N2O8P",
      "kind": "RNAp",
      "oneLetter": "T",
      "alternativeOneLetter": "τ",
      "ocl": {
        "value": "fncPK@I^aSbgIrtGc[pbxyDhhilheDiLjs`RuUUUSLuMDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
      },
      "mass": 320.1929965859354,
      "monoisotopicMass": 320.04095238282997,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ump": {
      "name": "Uridine monophosphate diradical",
      "mf": "C9H11N2O8P",
      "kind": "RNAp",
      "oneLetter": "U",
      "alternativeOneLetter": "υ",
      "ocl": {
        "value": "ff}PK@I^aSbgIsTGc[pbxyDhhilheDiLv\\BVjjjjYffbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
      },
      "mass": 306.1663791810886,
      "monoisotopicMass": 306.02530231837,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Rmp": {
      "name": "Ribose monophosphate diradical",
      "mf": "C5H7O6P",
      "kind": "RNAp",
      "ocl": {
        "value": "d@",
        "coordinates": ""
      },
      "mass": 194.07945630639637,
      "monoisotopicMass": 193.99802494145,
      "unsaturation": 4,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 7
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Adp": {
      "name": "Adenosine diphosphate diradical",
      "mf": "C10H13N5O9P2",
      "kind": "RNApp",
      "oneLetter": "A",
      "ocl": {
        "value": "fcoiH`INCt\\J\\UENU{Axv|F~DwGHeEEMeDheHd\\eHsg`u{UUUU@mAEMPQDqBId@@",
        "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPbOr_IorHbGtgD}F@RxPBuxc|_]^OTh}R_`CQ`MF@_`@_`A~"
      },
      "mass": 409.186273143011,
      "monoisotopicMass": 409.01885101411,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Cdp": {
      "name": "Cytidine diphosphate diradical",
      "mf": "C9H13N3O10P2",
      "kind": "RNApp",
      "oneLetter": "C",
      "ocl": {
        "value": "fe{ph`I^[BgENbgHy`|[^E_CkcdRbbfrbTRdqrdYpIZjjjieijZbHfHQL`@",
        "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPb@K_cbpXbKtSItwPS]@Bux`Bo]\\lFGx@S]A~@C}~@Gx"
      },
      "mass": 385.1615357477025,
      "monoisotopicMass": 385.00761762482,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Gdp": {
      "name": "Guanosine diphosphate diradical",
      "mf": "C10H13N5O10P2",
      "kind": "RNApp",
      "oneLetter": "G",
      "ocl": {
        "value": "fkhh`INCt\\J\\UENY{NCqmxM|EnNQJJJ[JIQJQHzIRLyxM^uUUUTkUSLuQDSDHfP@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_I`JHbGtgD}F@RxPBux`B_]^OTh}R_`CQ`B\\StXA~@C}~@Gx"
      },
      "mass": 425.1856780673293,
      "monoisotopicMass": 425.01376563368,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Tdp": {
      "name": "Thymidine diphosphate diradical",
      "mf": "C10H14N2O11P2",
      "kind": "RNApp",
      "oneLetter": "T",
      "ocl": {
        "value": "fmgQh`I^aSbgQSglu`|[^C_@[bdls^rruo}LxDmUUUTruTsTQDqBId@@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPbOs_cbpXbGtSItwPS]@Bux`B_]\\lFBpX_`AMtGx@Owx@_`"
      },
      "mass": 400.172914111366,
      "monoisotopicMass": 400.00728327219,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Udp": {
      "name": "Uridine diphosphate diradical",
      "mf": "C9H12N2O11P2",
      "kind": "RNApp",
      "oneLetter": "U",
      "ocl": {
        "value": "fe{Qh`I^aSbgQSehy`|[^E_CkcdRbbfrbTRdqrdYpIZjjjiejfZbHfHQL`@",
        "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPb@K_cbpXbKtSItwPS]@Bux`Bo]\\lFGx@S]A~@C}~@Gx"
      },
      "mass": 386.14629670651925,
      "monoisotopicMass": 385.99163320773005,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Atp": {
      "name": "Adenosine triphosphate diradical",
      "mf": "C10H14N5O12P3",
      "kind": "RNAppp",
      "oneLetter": "A",
      "ocl": {
        "value": "e`TZCJ@IG@nahJNEHdliemgo`OFspZ|CoByqrIQQSYQJIRIGIRWRL\\^AU]UUUUPKPQMTuABDpaBX`@",
        "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPbOr_IorHbGtgD}F@RxS|uxc|_]^OTh}R_`CQ`MF@@hcW@A~_`A~@@A~Owx"
      },
      "mass": 489.16619066844174,
      "monoisotopicMass": 488.98518190347005,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 12
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Ctp": {
      "name": "Cytidine triphosphate diradical",
      "mf": "C9H14N3O13P3",
      "kind": "RNAppp",
      "oneLetter": "C",
      "ocl": {
        "value": "fgqZ`I^[BgENbgOQsO\\Gc[pkxK|MnNQJJJ[JIQJSGJPzQg@ejjjjfVffjZbHfHQL`@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@K_cbpXbGtSItwPS]C|ux`B_]\\lFGx@S]@BbM\\B@Gy~@Gx@@Gx_`"
      },
      "mass": 465.1414532731331,
      "monoisotopicMass": 464.97394851418,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 13
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Gtp": {
      "name": "Guanosine triphosphate diradical",
      "mf": "C10H14N5O13P3",
      "kind": "RNAppp",
      "oneLetter": "G",
      "ocl": {
        "value": "eh\\ZKJ@IG@nahJNEHdliemco`POFspZ|KoAyqrIQQSYQJIRIGQJQzQccpJkjjjjjeZjYZijbDIaBDq@@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_I`JHbGtgD}F@RxPBux`B_]^OTh}R_`CQ`B\\StX@BbM_|@Gy~@Gx@@Gx_`"
      },
      "mass": 505.16559559276,
      "monoisotopicMass": 504.98009652304,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 13
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Ttp": {
      "name": "Thymidine triphosphate diradical",
      "mf": "C10H15N2O14P3",
      "kind": "RNAppp",
      "oneLetter": "T",
      "ocl": {
        "value": "eo`TGJ@IOHJNEGHdlnaiekg`OFspZ|Mo@yqrIQQSYQJIRY[ZPzQc`HjjjjjYZjVjZbDIaBDq@@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@K_cbpXbGtSItwPS]@Bux`B_]\\lFBpX_`AMt@JHupH@_gx@_`@@_c}~"
      },
      "mass": 480.15283163679663,
      "monoisotopicMass": 479.97361416155,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 14
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Utp": {
      "name": "Uridine triphosphate diradical",
      "mf": "C9H13N2O14P3",
      "kind": "RNAppp",
      "oneLetter": "U",
      "ocl": {
        "value": "fgPz`I^aSbgQSeoQsO\\Gc[pkxK|MnNQJJJ[JIQJSGJPzQg@ejjjjfVjVjZbHfHQL`@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@K_cbpXbGtSItwPS]C|ux`B_]\\lFGx@S]@BbM\\B@Gy~@Gx@@Gx_`"
      },
      "mass": 466.12621423194986,
      "monoisotopicMass": 465.95796409709004,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 14
      }, {
        "symbol": "P",
        "number": 3
      }]
    },
    "Ade": {
      "name": "Adenosine diradical",
      "mf": "C10H11N5O3",
      "kind": "RNA",
      "oneLetter": "A",
      "ocl": {
        "value": "fbmia@IV|gLJ\\Axj\\Tef[vyWV\\]zJZjjj`PJ`bIbDSH@",
        "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~i|BEP{iVA@fUARU@QTADBYPId"
      },
      "mass": 249.22643809214986,
      "monoisotopicMass": 249.08618923539,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Cyt": {
      "name": "Cytidine diradical",
      "mf": "C9H11N3O4",
      "kind": "RNA",
      "oneLetter": "C",
      "ocl": {
        "value": "fdypQ@INcBgK@|UNJRsM{\\~sg`uUUULmQDSDHfP@",
        "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~iRTBpgDq`@c`BNKB\\@c`"
      },
      "mass": 225.20170069684127,
      "monoisotopicMass": 225.0749558461,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 4
      }]
    },
    "Gua": {
      "name": "Guanosine diradical",
      "mf": "C10H11N5O4",
      "kind": "RNA",
      "oneLetter": "G",
      "ocl": {
        "value": "fj}hQ@IV|gLJ\\JCqTxiKLwmroKNN}EMUUUTkTuDQLPbY@@",
        "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~k|BEP{iVA@fUARU@QTADBYiVA@fP"
      },
      "mass": 265.22584301646816,
      "monoisotopicMass": 265.08110385496,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 4
      }]
    },
    "Thy": {
      "name": "Thymidine diradical",
      "mf": "C10H12N2O5",
      "kind": "RNA",
      "oneLetter": "T",
      "ocl": {
        "value": "fleQQ@INaSed`|UNJRsM{\\zlyxMUUUSMMDQLPbY@@",
        "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~iRTBpgDq`@c`BNKB\\lIpBN"
      },
      "mass": 240.21307906050478,
      "monoisotopicMass": 240.07462149347,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 5
      }]
    },
    "Ura": {
      "name": "Uridine diradical",
      "mf": "C9H10N2O5",
      "kind": "RNA",
      "oneLetter": "U",
      "ocl": {
        "value": "fdyQQ@INaSeh`|UNJRsM{\\~sg`uUUULsQDSDHfP@",
        "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~iRTBpgDq`@c`BNKB\\@c`"
      },
      "mass": 226.18646165565798,
      "monoisotopicMass": 226.05897142901,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 10
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 5
      }]
    },
    "Dam": {
      "name": "1,2′-O-dimethyladenosine monophosphate diradical 01A",
      "mf": "C12H16N5O6P",
      "kind": "NucleotideP",
      "oneLetter": "œ",
      "ocl": {
        "value": "feghs@E^ct\\J\\udhOEw`eqrIQQQKZIQJQIiLxFK^uUUUUKLtuQDSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@SuH"
      },
      "mass": 357.2595904272741,
      "monoisotopicMass": 357.08382025367,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dgm": {
      "name": "1,2′-O-dimethylguanosine monophosphate diradical 01G",
      "mf": "C12H16N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "ε",
      "ocl": {
        "value": "fmwis@E^ct\\J\\udlp^KoAKcdRbbbVtRbTbSbSNAbwmUUUURsMSUDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@B\\StPAOT`"
      },
      "mass": 373.2589953515923,
      "monoisotopicMass": 373.07873487324,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dim": {
      "name": "1,2′-O-dimethylinosine monophosphate diradical 019A",
      "mf": "C12O7N4H15P",
      "kind": "NucleotideP",
      "oneLetter": "ξ",
      "ocl": {
        "value": "fegIs@E^cvENZrTXOEw`eqrIQQQKZIQJQIiLxFK^uUUUUKLtuQDSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@SuH"
      },
      "mass": 358.2443513860907,
      "monoisotopicMass": 358.06783583658,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 4
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Tia": {
      "name": "2- methylthiomethylenethio-N6-isopentenyl-adenosine monophosphate diradical",
      "mf": "C17H24N5O6PS2",
      "kind": "NucleotideP",
      "oneLetter": "£",
      "ocl": {
        "value": "eh\\ZFJ@IG@nahJNEDl`OFspb\\V`cXHrIQQSYQJIRINIYIKQccpJkjjjjjAfBJjfjBDIaBDq@@",
        "coordinates": "!BpBYTvxBNFY|bEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~H@hc|_`BH_Xa}b@JH@gx@bGvH@h`B_`BH_P"
      },
      "mass": 489.50637075565066,
      "monoisotopicMass": 489.09056286031,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 17
      }, {
        "symbol": "H",
        "number": 24
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 2
      }]
    },
    "Mhc": {
      "name": "2′‐O‐Methyl-5-hydroxymethylcytidine monophosphate diradical",
      "mf": "C11H16N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "¡",
      "ocl": {
        "value": "fikpK@EA{BgM^rTXOEw`eqrIQQQKZIQJSJigHujjjjifYjkBHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@HoTuOSU@HC~NKA`HoQLgSUAMT@a}oS_|BBpXKAaMT@CQ"
      },
      "mass": 349.2342579562838,
      "monoisotopicMass": 349.06750148395,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Odg": {
      "name": "N2,2′-O-dimethylguanosine monophosphate diradical 02G",
      "mf": "C12H16N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "γ",
      "ocl": {
        "value": "fmwis@E^ct\\J\\udlp^KoAKcdRbbbVtRbTbSbsNAbwmUUUURsMSUDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@B\\StPAOT`"
      },
      "mass": 373.2589953515923,
      "monoisotopicMass": 373.07873487324,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ntg": {
      "name": "N2,N2,2′-O-trimethylguanosine monophosphate diradical 022G",
      "mf": "C13H18N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "|",
      "ocl": {
        "value": "fcois@E^ct\\J\\udlp^KoAKcdRbbbVtRbTbSbTYpLVcjjjjjVYjZjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuHgD}D@tPBNOt}R"
      },
      "mass": 387.2856127564392,
      "monoisotopicMass": 387.0943849377,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Otg": {
      "name": "N2,7,2′-O-trimethylguanosine monophosphate diradical 027G",
      "mf": "C13H20N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "æ",
      "ocl": {
        "value": "fcoisBE^bN\\J\\udjp^KoAKcFU}dRbbbVtRbTbRlQYpLVcjjjjjVYjjjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKFPMD@IqOQ@D}R"
      },
      "mass": 389.30149426455074,
      "monoisotopicMass": 389.11003500216,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Rya": {
      "name": "2′-O-ribosyladenosine monophosphate diradical 00A",
      "mf": "C15H20N5O9P",
      "kind": "NucleotideP",
      "oneLetter": "^",
      "ocl": {
        "value": "e`\\ZIL@DaegobFAIO@hlm`OGSp\\\\\\bbbfrRbdTT\\rbRQUCDQTrusuUUUUMUU@pET@@@",
        "coordinates": "!BIlAKaMARw}DBbMF@bGuMtHc|KAbH_ZU`@GzH_WwW@h`XKFjKB_jXB\\SiVA`zmG_Irp_hQKctvOSR\\lIrp"
      },
      "mass": 445.3217759066577,
      "monoisotopicMass": 445.09986424130005,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ryg": {
      "name": "2′-O-ribosylguanosine monophosphate diradical 00G",
      "mf": "C15H20N5O10P",
      "kind": "NucleotideP",
      "oneLetter": "ℑ",
      "ocl": {
        "value": "ehRZEL@DaegobFAIO@hlm`POGSp\\\\\\bbbfrRbdTT\\rbRQbhXbJfVn^jjjjijjjVZfj@@@",
        "coordinates": "!BIlAKaMARw}DBbMF@bGuMtH`BKAbH_ZU`@GzH_WwW@h`XKFjKB_jXB\\SiVA`zmG_Irp_hQKctvOSR\\lt]|gK@"
      },
      "mass": 461.321180830976,
      "monoisotopicMass": 461.09477886087,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Tmu": {
      "name": "2-thio-2′-O-methyluridine monophosphate diradical 02U",
      "mf": "C10H13N2O7PS",
      "kind": "NucleotideP",
      "oneLetter": "∏",
      "ocl": {
        "value": "fncQp`EAaSfleZCq]x^BDnNQJJJI[QJIRYlyFmUUUULsSQDSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@"
      },
      "mass": 336.25837906774416,
      "monoisotopicMass": 336.01810893766003,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Dmut": {
      "name": "3,2′-O-dimethyluridine monophosphate diradical 03U",
      "mf": "C11H15N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "σ",
      "ocl": {
        "value": "fasPK@EAaSfoYKtGb{pRxyDhhhemDheIhv\\cVjjjjfYjZHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXOxyMT@"
      },
      "mass": 334.2196139907822,
      "monoisotopicMass": 334.05660244729,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Amc": {
      "name": "N4-acetyl-2′-O-methylcytidine monophosphate diradical 042C",
      "mf": "C12H16N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "ℵ",
      "ocl": {
        "value": "fe{pK@EA[BgM^rTXOEw`eqrIQQQKZIQJSMJLyFmUUUULsMMQDSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@caLgSU@"
      },
      "mass": 361.244993853019,
      "monoisotopicMass": 361.06750148395,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Tmc": {
      "name": "N4,N4,2′-O-trimethylcytidine monophosphate diradical 044C",
      "mf": "C12H18N3O7P",
      "kind": "NucleotideP",
      "oneLetter": "β",
      "ocl": {
        "value": "fikqs@EA[BgM^rTGb{pRxyDhhhemDheIfhsdZuUUUTsLuTQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@cbpX"
      },
      "mass": 347.2614704368123,
      "monoisotopicMass": 347.08823692884005,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dcy": {
      "name": "N4,2′-O-dimethylcytidine monophosphate diradical 04C",
      "mf": "C11H16N3O7P",
      "kind": "NucleotideP",
      "oneLetter": "λ",
      "ocl": {
        "value": "fasqs@EA[BgM^rTGb{pRxyDhhhemDheIff\\cVjjjjfYfjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@lF@"
      },
      "mass": 333.23485303196554,
      "monoisotopicMass": 333.07258686438,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Muo": {
      "name": "2′-O-methyluridine 5-oxyacetic acid methyl ester monophosphate diradical 0503U",
      "mf": "C13H17N2O11P",
      "kind": "NucleotideP",
      "oneLetter": "Ͽ",
      "ocl": {
        "value": "fkoQk@EAaSfoYJwj}`|W^BWGHeEEDmheDiLjlif\\cVjjjjfYjZZhbIbDSH@",
        "coordinates": "!BKAb@tURD@m\\YpMAMpBYMcvjbOplIwx@bGuMc}\\Bb@JH@dvOcuKPSXa}bGvHH`BbGu~Oxc|bGt"
      },
      "mass": 408.25518206531905,
      "monoisotopicMass": 408.05699637046,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 17
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Xmu": {
      "name": "5-carboxymethylaminomethyl-2′-O-methyluridine monophosphate diradical 051U",
      "mf": "C13H18N3O10P",
      "kind": "NucleotideP",
      "oneLetter": ")",
      "ocl": {
        "value": "fkopk@EAGBgM^rWns`|W^BWGHeEEDmheDiLjleF\\cVjjjjfYjZfhbIbDSH@",
        "coordinates": "!BKAb@tURD@m\\YpMAMpBYMcvjb@HlIwx@bGuMc}\\Bb@JH@dvOcuKPSXa}bGvH@h`BbGvH@gx@bKt"
      },
      "mass": 407.2704211065024,
      "monoisotopicMass": 407.07298078755,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mmu": {
      "name": "5-methoxycarbonylmethyl-2′-O-methyluridine monophosphate diradical 0521U",
      "mf": "C13H17N2O10P",
      "kind": "NucleotideP",
      "oneLetter": "∩",
      "ocl": {
        "value": "fcwPk@EAaSfoYKvZp^KoAKcdRbbbVtRbTfUVfYrMZjjjjYfifjHbXaDr@@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lI}mK_`B@cm\\Bb@HlI}]}_`A~@BpgIqLXKH`Bb@I~@Ha}_c~HHa}"
      },
      "mass": 392.2557771410008,
      "monoisotopicMass": 392.06208175089,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 17
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Cue": {
      "name": "5-(carboxyhydroxymethyl)-2′-O-methyluridine methyl ester monophosphate diradical 0522U",
      "mf": "C13H17N2O11P",
      "kind": "NucleotideP",
      "oneLetter": "∩",
      "ocl": {
        "value": "fkoQk@EAaSfoYKtZ}`|W^BWGHeEEDmheDiLjhYf\\cVjjjjfYjZZhbIbDSH@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lI}mK_`B@cm\\Bb@HlI}]}_`A~@BpgIqLXKH`Bb@I~@Gx@bGu~Oxc|bGt"
      },
      "mass": 408.25518206531905,
      "monoisotopicMass": 408.05699637046,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 17
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Cyu": {
      "name": "5-carbamoylmethyl-2′-O-methyluridine monophosphate diradical 053U",
      "mf": "C12H16N3O9P",
      "kind": "NucleotideP",
      "oneLetter": "~",
      "ocl": {
        "value": "fmgqK@EAWBgM^rWlp^KoAKcdRbbbVtRbTfUVcNQkUUUUSLuLuDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXKAaMTDuPOxxlF@"
      },
      "mass": 377.24439877733727,
      "monoisotopicMass": 377.06241610352,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ipu": {
      "name": "5-(isopentenylaminomethyl)-2′-O-methyluridine monophosphate diradical 0583U",
      "mf": "C16H24N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "¼",
      "ocl": {
        "value": "fgpK@EAGBgM^rWhOEw`eqrIQQQKZIQJSJkIJLyFmUUUULsTuMTQDqBId@@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lI}mK_`B@cm\\Bb@HlI}]}_`A~@BpgIqLXKH`Bb@I~@Ha}b@JH_Xc|_`BH_P"
      },
      "mass": 417.35146347240624,
      "monoisotopicMass": 417.13010174179004,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 16
      }, {
        "symbol": "H",
        "number": 24
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mcy": {
      "name": "5,2′-O-dimethylcytidine monophosphate diradical monophosphate diradical 05C",
      "mf": "C11H16N3O7P",
      "kind": "NucleotideP",
      "oneLetter": "τ",
      "ocl": {
        "value": "fasqs@EA{BgM^rTGb{pRxyDhhhemDheIeV\\cVjjjjfYfjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXKAaMT@"
      },
      "mass": 333.23485303196554,
      "monoisotopicMass": 333.07258686438,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dmuf": {
      "name": "5,2′-O-dimethyluridine monophosphate diradical 05U",
      "mf": "C11H15N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "\\",
      "ocl": {
        "value": "fasPK@EAaSfoYKtGb{pRxyDhhhemDheIeV\\cVjjjjfYjZHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXKAaMT@"
      },
      "mass": 334.2196139907822,
      "monoisotopicMass": 334.05660244729,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Tma": {
      "name": "N6,N6,2′-O-trimethyladenosine monophosphate diradical 066A",
      "mf": "C13H18N5O6P",
      "kind": "NucleotideP",
      "oneLetter": "η",
      "ocl": {
        "value": "fmwhs@E^ct\\J\\udhOEw`eqrIQQQKZIQJQIkQg@q[vjjjj`Y`JjBHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@SuHXK@"
      },
      "mass": 371.2862078321209,
      "monoisotopicMass": 371.09947031813005,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Nda": {
      "name": "N6,2′-O-dimethyladenosine monophosphate diradical 06A",
      "mf": "C12H16N5O6P",
      "kind": "NucleotideP",
      "oneLetter": "χ",
      "ocl": {
        "value": "feghs@E^ct\\J\\udhOEw`eqrIQQQKZIQJQIkLxFK^uUUUTCLAUADSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@FBp"
      },
      "mass": 357.2595904272741,
      "monoisotopicMass": 357.08382025367,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Fmc": {
      "name": "5-formyl-2′-O-methylcytidine monophosphate diradical 071C",
      "mf": "C10H12N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "°",
      "ocl": {
        "value": "faspK@I^[BgENSghOFwaEqrIQQSYQJIRYULxDmUUUTsLttQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
      },
      "mass": 333.1917590433254,
      "monoisotopicMass": 333.03620135502996,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Omi": {
      "name": "2′-O-methylinosine monophosphate diradical 09A",
      "mf": "C11H13N4O7P",
      "kind": "NucleotideP",
      "oneLetter": "≤",
      "ocl": {
        "value": "fi{Is@E^cvENZrTXOEw`eqrIQQQKZIQJQIig@q[vjjjjiYffhbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@"
      },
      "mass": 344.21773398124395,
      "monoisotopicMass": 344.05218577211997,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 4
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Opu": {
      "name": "2′-O-methylpseudouridine monophosphate diradical 09U",
      "mf": "C10H13N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "Z",
      "ocl": {
        "value": "fncPK@@qaSfoYJtGb{pRxyDhhhemDheIfsdZuUUULuMMDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@"
      },
      "mass": 320.1929965859354,
      "monoisotopicMass": 320.04095238282997,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Oma": {
      "name": "2′-O-methyladenosine monophosphate diradical 0A",
      "mf": "C11H14N5O6P",
      "kind": "NucleotideP",
      "oneLetter": ":",
      "ocl": {
        "value": "fi{hs@E^ct\\J\\udhOEw`eqrIQQQKZIQJQIig@q[vjjjj`Y`J`bIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@"
      },
      "mass": 343.2329730224273,
      "monoisotopicMass": 343.06817018921,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Omc": {
      "name": "2′-O-methylcytidine monophosphate diradical 0C",
      "mf": "C10H14N3O7P",
      "kind": "NucleotideP",
      "oneLetter": "B",
      "ocl": {
        "value": "fncqs@EA[BgM^rTGb{pRxyDhhhemDheIfsdZuUUUTsLuDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@"
      },
      "mass": 319.2082356271187,
      "monoisotopicMass": 319.05693679992004,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Omg": {
      "name": "2′-O-methylguanosine monophosphate diradical 0G",
      "mf": "C11H14N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "#",
      "ocl": {
        "value": "fegis@E^ct\\J\\udlp^KoAKcdRbbbVtRbTbSbYpLV}jjjjjVYjZbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@HoTuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@B\\StP@"
      },
      "mass": 359.23237794674554,
      "monoisotopicMass": 359.06308480878,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Omu": {
      "name": "2′-O-methyluridinemonophosphate diradical 0U",
      "mf": "C10H13N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "J",
      "ocl": {
        "value": "fncPK@EAaSfoYJtGb{pRxyDhhhemDheIfsdZuUUUTsMMDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@"
      },
      "mass": 320.1929965859354,
      "monoisotopicMass": 320.04095238282997,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Cdg": {
      "name": "7-cyano-7-deazaguanosine monophosphate diradical 100G",
      "mf": "C12H12N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "φ",
      "ocl": {
        "value": "fmwis@INzM\\J\\TgLp^MoBKcdRbbfrbTRdRUbSN^CWmUUUUKLuSuDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StPCFP@"
      },
      "mass": 369.22723233536925,
      "monoisotopicMass": 369.04743474432,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Azg": {
      "name": "7-aminomethyl-7-deazaguanosine monophosphate diradical 101G",
      "mf": "C12H16N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "∉",
      "ocl": {
        "value": "fmwis@INzM\\J\\TgLp^MoBKcdRbbfrbTRdRUbSN^CWmUUUUKLuSUDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StPA`z`"
      },
      "mass": 373.2589953515923,
      "monoisotopicMass": 373.07873487324,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Eqo": {
      "name": "epoxyqueuosine monophosphate diradical 102G",
      "mf": "C17H22N5O10P",
      "kind": "NucleotideP",
      "oneLetter": "ς",
      "ocl": {
        "value": "el^ZEL@IGNaehJNEDlig`TPOFspb\\\\bTTTvTRbTbRlRjbbfXx|Bjz~aAajjjjiYfjZjjjjHPfDHSD@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StP@{ULY@TEIKA@a}tPA}BOpHAEP"
      },
      "mass": 487.3585341325581,
      "monoisotopicMass": 487.11042892533,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 17
      }, {
        "symbol": "H",
        "number": 22
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Aes": {
      "name": "archaeosine monophosphate diradical 103G",
      "mf": "C12H15N6O7P",
      "kind": "NucleotideP",
      "oneLetter": "(",
      "ocl": {
        "value": "fcoYs@INzM^xTxiNY`|[^DWGHeEEMeDheHdkDhsg`u{UUUURsMTmTQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StP@{UFCj"
      },
      "mass": 386.2577578089824,
      "monoisotopicMass": 386.07398384544,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Goq": {
      "name": "galactosyl-queuosine monophosphate diradical 104G",
      "mf": "C23H32N5O14P",
      "kind": "NucleotideP",
      "oneLetter": "9",
      "ocl": {
        "value": "ekXzGL@IGNaehJNEDliod\\VU]SPOFspb\\\\bTTTvTRbTbRlRjbTrTrbfRXx|Bjz^AyEjjjjiYfjZijjjjjjbDIaBDq@@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_IorHbGtgD}F@RxRH_WwW@hbOTh}RIlCQ`B\\StXC[UB[@RxSPT`JHbGwQ`H`BaEQ~@Ha}bOq~Ox`BbGu~@Ha}bOrH@`"
      },
      "mass": 633.4999767508004,
      "monoisotopicMass": 633.16833772591,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 23
      }, {
        "symbol": "H",
        "number": 32
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 14
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Gaq": {
      "name": "glutamyl-queuosine monophosphate diradical105G",
      "mf": "C22H29N6O12P",
      "kind": "NucleotideP",
      "oneLetter": "⊄",
      "ocl": {
        "value": "emWVCL@IGNaejXJNEDlioh\\YUPOFspb\\\\bTTTvTRbTbRlRjbTJTtrTXx|Bjz^AjjjjiYfjZijfjfjbDIaBDq@@",
        "coordinates": "!BTmB@c`JHUMmMtL@YtEHYgxQTaDoQ`L@YFY|gKMARH`Ygy|fpAfN`Hz@`H{PTb\\ltEIRtHBNHaTv|@YFYPTha}b@I~@Ha}_c~H@ha}bOq~@Ha}"
      },
      "mass": 600.473311954707,
      "monoisotopicMass": 600.15810739451,
      "unsaturation": 22,
      "elements": [{
        "symbol": "C",
        "number": 22
      }, {
        "symbol": "H",
        "number": 29
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 12
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Moq": {
      "name": "mannosyl-queuosine monophosphate diradical 106G",
      "mf": "C23H32N5O14P",
      "kind": "NucleotideP",
      "oneLetter": "8",
      "ocl": {
        "value": "ekXzGL@IGNaehJNEDliod\\VU]SPOFspb\\\\bTTTvTRbTbRlRjbTrTrbfRXx|Bjz^AyEjjjjiYfjZijjjjjjbDIaBDq@@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_IorHbGtgD}F@RxRH_WwW@hbOTh}RIlCQ`B\\StXC[UB[@RxSPT`JHbGwQ`H`BaEQ~@Ha}bOq~Ox`BbGu~@Ha}bOrH@`"
      },
      "mass": 633.4999767508004,
      "monoisotopicMass": 633.16833772591,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 23
      }, {
        "symbol": "H",
        "number": 32
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 14
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Qus": {
      "name": "queuosine monophosphate diradical 10G",
      "mf": "C17H22N5O9P",
      "kind": "NucleotideP",
      "oneLetter": "Q",
      "ocl": {
        "value": "edZZIL@IGNaehJNEDliohPOFspb\\\\bTTTvTRbTbRlRjbTKGG`UWSpMUUUUKLuSUMUTPaLHPfH@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPHoWtw@aOTd}RqdCQ@B\\StP@{ULY@RpQPTopHBGwQ@@QT"
      },
      "mass": 471.35912920823984,
      "monoisotopicMass": 471.11551430576,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 17
      }, {
        "symbol": "H",
        "number": 22
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Cpo": {
      "name": "1-methyl-3-(3-amino-3-carboxypropyl)pseudouridine monophosphate diradical 1309U",
      "mf": "C14H20N3O10P",
      "kind": "NucleotideP",
      "oneLetter": "α",
      "ocl": {
        "value": "fgpk@OAWBgENSgi{`|[^DWGHeEEMeDheIhjbihs`RuUUTsTuSUMQDSDHfP@",
        "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}DqbH@gx_c|SFA`lIqOW_Xa}uwu~Ox`BbGu~Ox`B_`BH_P"
      },
      "mass": 421.2970385113492,
      "monoisotopicMass": 421.08863085201,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 14
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mls": {
      "name": "1-methylinosine monophosphate diradical 19A",
      "mf": "C11H13N4O7P",
      "kind": "NucleotideP",
      "oneLetter": "O",
      "ocl": {
        "value": "fi{Is@INBvENJSghOFwaEqrIQQSYQJIRIMIgOAjvjjjjefZZhbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}R"
      },
      "mass": 344.21773398124395,
      "monoisotopicMass": 344.05218577211997,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 4
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mpu": {
      "name": "1-methylpseudouridine monophosphate diradical 19U",
      "mf": "C10H13N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "]",
      "ocl": {
        "value": "fncPK@OAaSbgIrtGc[pbxyDhhilheDiLjs`RuUUTsTuMDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
      },
      "mass": 320.1929965859354,
      "monoisotopicMass": 320.04095238282997,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mad": {
      "name": "1-methyladenosine monophosphate diradical 1A",
      "mf": "C11H14N5O6P",
      "kind": "NucleotideP",
      "oneLetter": "\"",
      "ocl": {
        "value": "fi{hs@INBwlJ\\TgHOFwaEqrIQQSYQJIRIMIgOAjvjjjjefZZhbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}R"
      },
      "mass": 343.2329730224273,
      "monoisotopicMass": 343.06817018921,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mgs": {
      "name": "1-methylguanosine monophosphate diradical 1G",
      "mf": "C11H14N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "K",
      "ocl": {
        "value": "fegis@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\RYspZmjjjjiYfijbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtP@gD}D@SuH"
      },
      "mass": 359.23237794674554,
      "monoisotopicMass": 359.06308480878,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Msu": {
      "name": "5-aminomethyl-2-selenouridine monophosphate diradical 20510U",
      "mf": "C10H14N3O7PSe",
      "kind": "NucleotideP",
      "oneLetter": "π",
      "ocl": {
        "value": "fasqp`I^{BgEIrtGc[p\\bQ\\\\bTTTvTRbTfUSNAKUUUULsTuDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
      },
      "mass": 398.1676241841323,
      "monoisotopicMass": 398.97345859992004,
      "unsaturation": null,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "Se",
        "number": 1
      }]
    },
    "Mse": {
      "name": "5-methylaminomethyl-2-selenouridine monophosphate diradical 20511U",
      "mf": "C11H16N3O7PSe",
      "kind": "NucleotideP",
      "oneLetter": "≅",
      "ocl": {
        "value": "fikqp`I^{BgEIrtGc[p\\bQ\\\\bTTTvTRbTfUVYpIZjjjifZfjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTBpX"
      },
      "mass": 412.19424158897914,
      "monoisotopicMass": 412.98910866438,
      "unsaturation": null,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "Se",
        "number": 1
      }]
    },
    "Cse": {
      "name": "5-carboxymethylaminomethyl-2-selenouridine monophosphate diradical 2051U",
      "mf": "C12H16N3O9PSe",
      "kind": "NucleotideP",
      "oneLetter": "⊥",
      "ocl": {
        "value": "fcwqH`I^{BgEIru^p^MoArIEqrIQQSYQJIRYUYJLxDmUUUTsMSTuDQLPbY@@",
        "coordinates": "!BKAb@tURDM\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@I~@Ha}"
      },
      "mass": 456.20378733435086,
      "monoisotopicMass": 456.97893790352,
      "unsaturation": null,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "Se",
        "number": 1
      }]
    },
    "Agm": {
      "name": "agmatidine monophosphate diradical 20C",
      "mf": "C14H26N7O6P",
      "kind": "NucleotideP",
      "oneLetter": "¿",
      "ocl": {
        "value": "fgxs@I^BuY{piqR\\`|[^DWGHeEEMeDeEHmUddhsgbuUUUSTuUUMIDSDHfP@",
        "coordinates": "!BDqc_tTnD_]\\fpH}MgrYRc}_|Dr_W_Wx@ThWM_|bOqRc}ARctu~@Gx@urH@gx@b@I~@H`BbGu~@@"
      },
      "mass": 419.373876184194,
      "monoisotopicMass": 419.16821858483,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 14
      }, {
        "symbol": "H",
        "number": 26
      }, {
        "symbol": "N",
        "number": 7
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Sou": {
      "name": "2-selenouridine monophosphate diradical 20U",
      "mf": "C9H11N2O7PSe",
      "kind": "NucleotideP",
      "oneLetter": "ω",
      "ocl": {
        "value": "ff}Qp`I^aSbdyjCqmxNQHnNQJJJ[JIQJSMg@ejjjjfYihbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
      },
      "mass": 369.1263628137839,
      "monoisotopicMass": 369.9469094988,
      "unsaturation": null,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "Se",
        "number": 1
      }]
    },
    "Agu": {
      "name": "5-aminomethyl-2-geranylthiouridine monophosphate diradical 21510U",
      "mf": "C20H30N3O7PS",
      "kind": "NucleotideP",
      "oneLetter": "Δ",
      "ocl": {
        "value": "ed\\\\NB@IOIhJNEDla`OFsp\\BHgGHeEEMeDheHdjdcEdhqpEUUUUURsUSMTuQBDpaBXdDt@",
        "coordinates": "!BDr__cdo[_X`fgx}RgqeRtM]}Dqa~O}\\BTmBH_]]}uwuRtMAMcuI~O}\\BupJH_]]}_`A~Oxa}uwu~Oxa}_cW_Xa}"
      },
      "mass": 487.5074340654907,
      "monoisotopicMass": 487.15420849000003,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 20
      }, {
        "symbol": "H",
        "number": 30
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mgu": {
      "name": "5-methylaminomethyl-2-geranylthiouridine monophosphate diradical 21511U",
      "mf": "C21H32N3O7PS",
      "kind": "NucleotideP",
      "oneLetter": "h",
      "ocl": {
        "value": "elR\\NB@IOIhJNEDla`OFsp\\BHgGHeEEMeDheHdjdlileFN@jjjjjjVZjYjijbDIaBDqHIh",
        "coordinates": "!BTv^cbn{__@fw|}RwqeRdK]}Tva~_{_|TiCp_[]}mwuRdIAMsuI~_{]|mwsp_[]}mwu~_{_||Gvw_Wy|Gu~_{]}|Gt"
      },
      "mass": 501.5340514703375,
      "monoisotopicMass": 501.16985855446006,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 21
      }, {
        "symbol": "H",
        "number": 32
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Cgu": {
      "name": "5-carboxymethylaminomethyl-2-geranylthiouridine monophosphate diradical 2151U",
      "mf": "C22H32N3O9PS",
      "kind": "NucleotideP",
      "oneLetter": "f",
      "ocl": {
        "value": "ef^\\IB@IOIhJNEDla`XPOFsp\\BHgGHeEEMeDheHdjdlhehbhqpEUUUUURsUSMUMMTPaLHPfIAM@",
        "coordinates": "!BTv^cbn{_@fw|}RwqeRdK]}Tva~_{]|TiCp[_}muRdIAMsuI~_{]|mwsp_[]}mwu~_{]||Gvw_[_}_g}~_{]||Ou~_{]}|Gt"
      },
      "mass": 545.5435972157093,
      "monoisotopicMass": 545.1596877935999,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 22
      }, {
        "symbol": "H",
        "number": 32
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mha": {
      "name": "2-methylthio-N6-(cis-hydroxyisopentenyl) adenosine monophosphate diradical 2160A",
      "mf": "C16H22N5O7PS",
      "kind": "NucleotideP",
      "oneLetter": "≠",
      "ocl": {
        "value": "e`TZNB@IG@nahJNEDlo`OFspb\\V`cHeEEMeDheHdxeleDqqxEUuUUUU@sAETuTDHSBDIbP[P",
        "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]WHc|TmCQw}~N`ME~@Gx@upJH@h`B_`BH_X`BbGvHGxbGt"
      },
      "mass": 459.41437086899504,
      "monoisotopicMass": 459.09775624102,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 16
      }, {
        "symbol": "H",
        "number": 22
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mpa": {
      "name": "2-methylthio-N6-isopentenyladenosine monophosphate diradical 2161A",
      "mf": "C16H22N5O6PS",
      "kind": "NucleotideP",
      "oneLetter": "*",
      "ocl": {
        "value": "eohZFB@IG@nahJNEDl`OFspb\\V`cHeEEMeDheHdxeleFNO@jnjjjjhFXHjfjBDIaBDq@@",
        "coordinates": "!BpBYTvxBNFY|bEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~H@h`B_`BH_Xa}bOrH@ha}b@I~@Ha}"
      },
      "mass": 443.4149659446768,
      "monoisotopicMass": 443.10284162145,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 16
      }, {
        "symbol": "H",
        "number": 22
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mca": {
      "name": "2-methylthio-N6-threonylcarbamoyladenosine monophosphate diradical 2162A",
      "mf": "C16H21N6O10PS",
      "kind": "NucleotideP",
      "oneLetter": "[",
      "ocl": {
        "value": "ebVVEB@IG@nachJNEDlm`XTPOFspb\\V`cHeEEMeDheHdxemLhhhqqxEUuUUUU@sAESUMUABDpaBX`@",
        "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@upJH@h`B_`BH_Wxb@JH_WxbOrHo]^}_`BH_P"
      },
      "mass": 520.4113480993399,
      "monoisotopicMass": 520.07774907193,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 16
      }, {
        "symbol": "H",
        "number": 21
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mva": {
      "name": "2-methylthio-N6-hydroxynorvalylcarbamoyladenosine monophosphate diradical 2163A",
      "mf": "C17H23N6O10PS",
      "kind": "NucleotideP",
      "oneLetter": "≈",
      "ocl": {
        "value": "ej^VEB@IG@nachJNEDlm`XTPOFspb\\V`cHeEEMeDheHdxemLhhiVNO@jnjjjjhFXHjZijjBDIaBDq@@",
        "coordinates": "!BpBYTvxBNFY|BbEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~H@h`B_`BH_Xa}bOrH@gx@bGvHGx@bGwW@h`B_c~H@ha}"
      },
      "mass": 534.4379655041866,
      "monoisotopicMass": 534.09339913639,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 17
      }, {
        "symbol": "H",
        "number": 23
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mya": {
      "name": "2-methylthio cyclic N6-threonylcarbamoyladenosine monophosphate diradical 2164A",
      "mf": "C17H20N5O9PS",
      "kind": "NucleotideP",
      "oneLetter": "ÿ",
      "ocl": {
        "value": "elVZIB@IG@nkhJNEDlcghPOFspb\\V`cHeEEMeDheHdxeihiUFNO@jnkojjjjhFXHjfZjbHPfDHSD@@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_IorHbGtgD}F@RxRH_WwW@hbOTh}RIqOQ`MF@cuKW@hQTcttfpL@YS]@BbGvH@Gx"
      },
      "mass": 501.4080351062552,
      "monoisotopicMass": 501.07193541570007,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 17
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Hta": {
      "name": "hydroxy-N6-threonylcarbamoyladenosine monophosphate diradical 2165A",
      "mf": "C15H19N6O11P",
      "kind": "NucleotideP",
      "oneLetter": "«",
      "ocl": {
        "value": "elZVML@IG@fnehJNEDligo`TPOFspb\\\\bTTTvTRbTbSVTrbbeXx|BjZjjjj`Y`JZijjBDIaBDq@@",
        "coordinates": "!BpBYTvxBNFY|bEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~HH`BbGvH_Xc|_`BH_Xc|_`BH_]_|bOq~Oxc|bGt"
      },
      "mass": 490.31934821268436,
      "monoisotopicMass": 490.08494245264,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 19
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Lyd": {
      "name": "2-lysidine monophosphate diradical 21C",
      "mf": "C15H24N5O8P",
      "kind": "NucleotideP",
      "oneLetter": "}",
      "ocl": {
        "value": "eo`ZAL@IGOFmhJNEDlkg`OFspb\\\\bTTTvTRbTbSVRTtXxBJjjjjfYjZjfhaBXPaLP@",
        "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}Dqa~Oxc|_c|SFA`lIqOW_Xa}_c~HHa}bOrH_WxbOq~@Ha}"
      },
      "mass": 433.3541339985626,
      "monoisotopicMass": 433.13624975064994,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 24
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Gtu": {
      "name": "2-geranylthiouridine monophosphate diradical 21U",
      "mf": "C19H27N2O7PS",
      "kind": "NucleotideP",
      "oneLetter": "Γ",
      "ocl": {
        "value": "e`XTNB@IOHJNEDln`OFsp\\BHgGHeEEMeDheHdtmEdhqpEUUUUURsUKUMTPaLHPfIAu@",
        "coordinates": "!BTv^cbn{__@fw|}RwqeRdK]}Tva~_{_|TiCp_[]}mwuRdIAMsuI~_{]||Gvw_Wy|Gvw_Wy|Gu~_{]}|Gt"
      },
      "mass": 458.46617269514235,
      "monoisotopicMass": 458.12765938888003,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 19
      }, {
        "symbol": "H",
        "number": 27
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Tyg": {
      "name": "N2,N2,7-trimethylguanosine cap monophosphate diradical (cap TMG) 2279553N",
      "mf": "C13H20N5O10P2",
      "kind": "NucleotideP",
      "oneLetter": "¶",
      "ocl": {
        "value": "e`TZEBHIG@aihJNEHdleck`OFspz|MgDJTef[vVVe_gifNO@jijjjjjUijifjhaBXPaLP@",
        "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPbOr_I`JHbGtgD}F@RxS|uxc|_]^OTh}RIlA~@B\\StXCQ`Gx@Owx@_h{_cuH"
      },
      "mass": 468.2734710359255,
      "monoisotopicMass": 468.06854085929,
      "unsaturation": 13,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Tmg": {
      "name": "N2,N2,7-trimethylguanosine monophosphate diradical 227G",
      "mf": "C13H20N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "∠",
      "ocl": {
        "value": "fcoisBINCt\\J\\TgLp^MoBKbFY}dRbbfrbTRdRUbtYspZcjjjjiYfjjjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}Rqd@gD}D@tPBNOt}R"
      },
      "mass": 389.30149426455074,
      "monoisotopicMass": 389.11003500216,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dgu": {
      "name": "N2,N2-dimethylguanosine monophosphate diradical 22G",
      "mf": "C12H16N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "R",
      "ocl": {
        "value": "fmwis@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\RcN^CWmUUUUKLuMUDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RIqOQ@MD@cc}OT`"
      },
      "mass": 373.2589953515923,
      "monoisotopicMass": 373.07873487324,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Atu": {
      "name": "5-aminomethyl-2-thiouridine monophosphate diradical 2510U",
      "mf": "C10H14N3O7PS",
      "kind": "NucleotideP",
      "oneLetter": "∫",
      "ocl": {
        "value": "fasqp`I^{BgEIrtGc[p\\DQ\\\\bTTTvTRbTfUSNAKUUUULsTuDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
      },
      "mass": 351.27302303324575,
      "monoisotopicMass": 351.02900797432005,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mou": {
      "name": "5-methylaminomethyl-2-thiouridine monophosphate diradical 2511U",
      "mf": "C11H16N3O7PS",
      "kind": "NucleotideP",
      "oneLetter": "S",
      "ocl": {
        "value": "fikqp`I^{BgEIrtGc[p\\DQ\\\\bTTTvTRbTfUVYpIZjjjifZfjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTBpX"
      },
      "mass": 365.2996404380926,
      "monoisotopicMass": 365.04465803878,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Ctu": {
      "name": "5-carboxymethylaminomethyl-2-thiouridine monophosphate diradical 251U",
      "mf": "C12H16N3O9PS",
      "kind": "NucleotideP",
      "oneLetter": "$",
      "ocl": {
        "value": "fcwqH`I^{BgEIru^p^MoApQEqrIQQSYQJIRYUYJLxDmUUUTsMSTuDQLPbY@@",
        "coordinates": "!BKAb@tURDM\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@I~@Ha}"
      },
      "mass": 409.3091861834643,
      "monoisotopicMass": 409.03448727792,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Myu": {
      "name": "5-methoxycarbonylmethyl-2-thiouridine monophosphate diradical 2521U",
      "mf": "C12H15N2O9PS",
      "kind": "NucleotideP",
      "oneLetter": "3",
      "ocl": {
        "value": "fmgQH`I^aSbdyZNXOFw`xHbxyDhhilheDiLjmLs`RuUUUSLuLuQDSDHfP@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{WHc|KB_W_Wx@_`@lIr\\SFBrH@h`B_`BH_WxbOrH_P"
      },
      "mass": 394.2945422179627,
      "monoisotopicMass": 394.02358824126003,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Cou": {
      "name": "5-carbamoylmethyl-2-thiouridine monophosphate diradical 253U",
      "mf": "C11H14N3O8PS",
      "kind": "NucleotideP",
      "oneLetter": "l",
      "ocl": {
        "value": "fe{pH`I^gBgEIrtXOFw`xHbxyDhhilheDiLjmF\\BVjjjjYfifhbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTC~NKA`"
      },
      "mass": 379.2831638542993,
      "monoisotopicMass": 379.02392259389,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Cau": {
      "name": "5-carboxymethyl-2-thiouridine monophosphate diradical 2540U",
      "mf": "C11H13N2O9PS",
      "kind": "NucleotideP",
      "oneLetter": "℘",
      "ocl": {
        "value": "fe{QH`I^aSbdyZNXOFw`xHbxyDhhilheDiLjmF\\BVjjjjYfifhbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTC~NKA`"
      },
      "mass": 380.26792481311594,
      "monoisotopicMass": 380.00793817680005,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Tau": {
      "name": "5-taurinomethyl-2-thiouridine monophosphate diradical 254U",
      "mf": "C12H18N3O10PS2",
      "kind": "NucleotideP",
      "oneLetter": "∃",
      "ocl": {
        "value": "fgpj`I^{BgEIrwY{`|[^C`bKblHrIQQSYQJIRYUYIRLxDmUUUTsMSUKTQDqBId@@",
        "coordinates": "!BKAb@tURD@m\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@JH__rH_]^H_P"
      },
      "mass": 459.3892600220213,
      "monoisotopicMass": 459.01712313635005,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 2
      }]
    },
    "Itu": {
      "name": "5-(isopentenylaminomethyl)-2-thiouridine monophosphate diradical 2583U",
      "mf": "C15H22N3O7PS",
      "kind": "NucleotideP",
      "oneLetter": "½",
      "ocl": {
        "value": "fkoqp`I^{BgEIrtGc[p\\DQ\\\\bTTTvTRbTfUVRTYpIZjjjifZfijbHfHQL`@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{W@h`BKB_W_Wx@_`@lIr\\SFBrH@h`B_`BH_Xc|bGvH@gx@bGt"
      },
      "mass": 419.3902285493682,
      "monoisotopicMass": 419.09160823216,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 22
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Mth": {
      "name": "5-methyl-2-thiouridine monophosphate diradical 25U",
      "mf": "C10H13N2O7PS",
      "kind": "NucleotideP",
      "oneLetter": "F",
      "ocl": {
        "value": "fncQp`I^aSbdyZCqmxNBHnNQJJJ[JIQJSJlxDmUUUTsMSQDSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
      },
      "mass": 336.25837906774416,
      "monoisotopicMass": 336.01810893766003,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Dmg": {
      "name": "N2,7-dimethylguanosine monophosphate diradical 27G",
      "mf": "C12H18N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "∨",
      "ocl": {
        "value": "fmwisBINCt\\J\\TgLp^MoBKbFY}dRbbfrbTRdRUbKN^CWmUUUUKLuUUDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StPAOT`"
      },
      "mass": 375.27487685970397,
      "monoisotopicMass": 375.0943849377,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dma": {
      "name": "2,8-dimethyladenosine monophosphate diradical 28A",
      "mf": "C12H16N5O6P",
      "kind": "NucleotideP",
      "oneLetter": "±",
      "ocl": {
        "value": "feghs@INCv\\J\\UdhOFw`eqrIQQSYQJJJQKqLyxK^uUUUPMLAUADSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpP@c`a}_S_|BD}RSuKQ@B\\StP@"
      },
      "mass": 357.2595904272741,
      "monoisotopicMass": 357.08382025367,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mas": {
      "name": "2-methyladenosine monophosphate diradical 2A",
      "mf": "C11H14N5O6P",
      "kind": "NucleotideP",
      "oneLetter": "/",
      "ocl": {
        "value": "fi{hs@INBt\\J\\TgHOFwaEqrIQQSYQJIRINIgOAjvjjjjAf@j`bIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtP@gD}D@"
      },
      "mass": 343.2329730224273,
      "monoisotopicMass": 343.06817018921,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Tcy": {
      "name": "2-thiocytidine monophosphate diradical 2C",
      "mf": "C9H12N3O6PS",
      "kind": "NucleotideP",
      "oneLetter": "%",
      "ocl": {
        "value": "ff}pp`I^kBgEIrCqmxNBHnNQJJJ[JIQJSMg@ejjjjfYfhbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
      },
      "mass": 321.2470007040807,
      "monoisotopicMass": 321.01844329029,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Nmg": {
      "name": "N2-methylguanosine monophosphate diradical 2G",
      "mf": "C11H14N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "L",
      "ocl": {
        "value": "fegis@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\VYspZmjjjjiYfijbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtP@gD}D@SuH"
      },
      "mass": 359.23237794674554,
      "monoisotopicMass": 359.06308480878,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Thu": {
      "name": "2-thiouridine monophosphate diradical 2U",
      "mf": "C9H11N2O7PS",
      "kind": "NucleotideP",
      "oneLetter": "2",
      "ocl": {
        "value": "ff}Qp`I^aSbdyjCqmxNBHnNQJJJ[JIQJSMg@ejjjjfYihbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
      },
      "mass": 322.2317616628973,
      "monoisotopicMass": 322.0024588732,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Ahu": {
      "name": "3-(3-amino-3-carboxypropyl)-5,6-dihydrouridine monophosphate diradical 308U",
      "mf": "C13H20N3O10P",
      "kind": "NucleotideP",
      "oneLetter": "Ð",
      "ocl": {
        "value": "fkopk@I^gBgENSens`|[^DWGHeEEMeDheIhueMF\\BVjjjjZfijfhbIbDSH@",
        "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}DqbH@gx_c|SFA`lIqOW_Xa}_c~HHa}_c~H@gx@bGt"
      },
      "mass": 409.28630261461393,
      "monoisotopicMass": 409.08863085201,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "App": {
      "name": "3-(3-amino-3-carboxypropyl)pseudouridine monophosphate diradical 309U",
      "mf": "C13H18N3O10P",
      "kind": "NucleotideP",
      "oneLetter": "Þ",
      "ocl": {
        "value": "fkopk@OAgBgENSens`|[^DWGHeEEMeDheIhueMF\\BVjjjfZfijfhbIbDSH@",
        "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}DqbH@gx_c|SFA`lIqOW_Xa}_c~HHa}_c~H@gx@bGt"
      },
      "mass": 407.2704211065024,
      "monoisotopicMass": 407.07298078755,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Apu": {
      "name": "3-(3-amino-3-carboxypropyl)uridine monophosphate diradical 30U",
      "mf": "C13H18N3O10P",
      "kind": "NucleotideP",
      "oneLetter": "X",
      "ocl": {
        "value": "fkopk@I^gBgENSens`|[^DWGHeEEMeDheIhueMF\\BVjjjjYfijfhbIbDSH@",
        "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}DqbH@gx_c|SFA`lIqOW_Xa}_c~HHa}_c~H@gx@bGt"
      },
      "mass": 407.2704211065024,
      "monoisotopicMass": 407.07298078755,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mws": {
      "name": "methylwyosine monophosphate diradical 342G",
      "mf": "C15H18N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "∑",
      "ocl": {
        "value": "eghZNL@IG@nahJNEDli`OFspb\\\\bTTTvTRbTbb\\rVSGG`SPrvuUUUUKMTsUUIBDpaBX`@",
        "coordinates": "!B_`CW@mF@ctvDUI|fRxPYgtwP[zV_IorHFY|gD}F@RxPYg|@YgrZOTh{_cuJOS]F@tXAKaI|fw}EMt@"
      },
      "mass": 411.3070845499097,
      "monoisotopicMass": 411.0943849377,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Uhw": {
      "name": "undermodified hydroxywybutosine monophosphate diradical 3470G",
      "mf": "C18H23N6O10P",
      "kind": "NucleotideP",
      "oneLetter": "š",
      "ocl": {
        "value": "ejQVEL@IG@nahXJNEDliolRPOFspb\\\\bTTTvTRbTbb\\rVVTttXx|BZFVvjjjjiYjfZjjfjRDIaBDq@@",
        "coordinates": "!BKB^@ceS[H`Yg}ARpAeMtHa}KAcPTh{_S]CjXES[pAeMtH}MtEK@IdnDpBXBbES[UMo@F]ARaERH_X`B_`BH_WxbOq~@Ha}"
      },
      "mass": 514.3839139947949,
      "monoisotopicMass": 514.12132796199,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 18
      }, {
        "symbol": "H",
        "number": 23
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Acw": {
      "name": "7-aminocarboxypropylwyosine monophosphate diradical 347G",
      "mf": "C18H23N6O9P",
      "kind": "NucleotideP",
      "oneLetter": "Ω",
      "ocl": {
        "value": "eb^VIL@IG@na`XJNEDlid\\POFspb\\\\bTTTvTRbTbb\\rVRrfcGG`SPrvuUUUUKMTsUUSUIBDpaBX`@",
        "coordinates": "!BDr]RcwwWpAg_tUS[cm~DUAf_XJUTvx}MaEP@_gwWcm~DUDnDUMo|urH@m_@FWwW_]^NwuS[bGtYgx`BbGu~Ox`B_`BH_P"
      },
      "mass": 498.38450907047655,
      "monoisotopicMass": 498.12641334242,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 18
      }, {
        "symbol": "H",
        "number": 23
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hwy": {
      "name": "methylated undermodified hydroxywybutosine monophosphate diradical 3480G",
      "mf": "C19H25N6O10P",
      "kind": "NucleotideP",
      "oneLetter": "y",
      "ocl": {
        "value": "efYVEL@IG@nahXJNEDliolRPOFspb\\\\bTTTvTRbTbb\\rVVTttsGG`SPrvuUUUUKMTsUUTuTdHSBDIb@@",
        "coordinates": "!B`HyRtL@f_XbDRxz@UHS_chc|S]BN`MAMwxyKaL@fUHS_cmG_chCjXI|YzfA}bL@fpBYTaHz@F\\BH@gx@upJH@ha}_`CWHc|_`@"
      },
      "mass": 528.4105313996416,
      "monoisotopicMass": 528.1369780264499,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 19
      }, {
        "symbol": "H",
        "number": 25
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hwb": {
      "name": "hydroxywybutosine monophosphate diradical 34830G",
      "mf": "C21H27N6O12P",
      "kind": "NucleotideP",
      "oneLetter": "⊆",
      "ocl": {
        "value": "ee[VCL@IG@nahXJNEDliobZV^POFspb\\\\bTTTvTRbTbb\\rVVTtRbfsGG`SPrvuUUUUKMTsUUULuUIBDpaBX`@",
        "coordinates": "!BKB^@ceS[@h`Yg}ARpAeMtHa}KAcPTh{_S]CjXES[pAeMtH}MtEK@IdnDpBXBbES[UMo@F]ARaERH_X`B_`BH_X`B_c~H_]]}bGu~Ox`B_c~H_P"
      },
      "mass": 586.4466945498602,
      "monoisotopicMass": 586.14245733005,
      "unsaturation": 22,
      "elements": [{
        "symbol": "C",
        "number": 21
      }, {
        "symbol": "H",
        "number": 27
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 12
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Pwb": {
      "name": "peroxywybutosine monophosphate diradical 34832G",
      "mf": "C21H27N6O13P",
      "kind": "NucleotideP",
      "oneLetter": "W",
      "ocl": {
        "value": "emWVKL@IG@nadXJNEDliohZV^QPOFspb\\\\bTTTvTRbTbb\\rVVTRfTTvXx|BZFVvjjjjiYjfZjjjYjjRDIaBDq@@",
        "coordinates": "!BKB^@ceS[@h`Yg}ARpAeMtHa}KAcPTh{_S]CjXES[pAeMtH}MtEK@IdnDpB[|bES[UMo@F]ARaERH_X`B_`BH_X`Bb@I~Oxa}uwvH_Wxb@I~Oxa}"
      },
      "mass": 602.4460994741785,
      "monoisotopicMass": 602.1373719496199,
      "unsaturation": 22,
      "elements": [{
        "symbol": "C",
        "number": 21
      }, {
        "symbol": "H",
        "number": 27
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 13
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Wyb": {
      "name": "wybutosine monophosphate diradical 3483G",
      "mf": "C21H27N6O11P",
      "kind": "NucleotideP",
      "oneLetter": "Y",
      "ocl": {
        "value": "eiSVML@IG@na`XJNEDlilRZVPOFspb\\\\bTTTvTRbTbb\\rVVRbTTvXx|BZFVvjjjjiYjfZjjfZjdaBXPaLP@",
        "coordinates": "!BsJ\\@ciP{@`YWuARPAeMT@a}sNaPThxSUCjhIP{PAeMTD}MTEI@IllDPB[|BIP{eCm@FUARAIPH_Pc|BGtHGzBGtw_Pa}_k|HGzBGt"
      },
      "mass": 570.4472896255419,
      "monoisotopicMass": 570.14754271048,
      "unsaturation": 22,
      "elements": [{
        "symbol": "C",
        "number": 21
      }, {
        "symbol": "H",
        "number": 27
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Awo": {
      "name": "7-aminocarboxypropylwyosine methyl ester monophosphate diradical 348G",
      "mf": "C19H25N6O9P",
      "kind": "NucleotideP",
      "oneLetter": "⇑",
      "ocl": {
        "value": "ejQVIL@IG@na`XJNEDlid\\POFspb\\\\bTTTvTRbTbb\\rVVRffXx|BZFVvjjjjiYjfZjjZjRDIaBDq@@",
        "coordinates": "!B`HyRtL@f_XbDRxz@UHS_ch`BS]BN`MAMwxyKaL@fUHS_cmG_chCjXI|YzfA}bL@fpBYTaHz@F\\BHHa}bOq~@Ha}_c~H@ha}"
      },
      "mass": 512.4111264753234,
      "monoisotopicMass": 512.14206340688,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 19
      }, {
        "symbol": "H",
        "number": 25
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Wyo": {
      "name": "wyosine monophosphate diradical 34G",
      "mf": "C14H16N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "€",
      "ocl": {
        "value": "ek`ZNL@IG@nahJNEDli`OFspb\\\\bTTTvTRbTbb\\rVXx|BZFVvjjjjiYjfZjdaBXPaLP@",
        "coordinates": "!B_`CWMF@ctvDUI|fRxPYgtwP[zV_IorHFY|gD}F@RxPYg|@YgrZOTh{_cuJOS]F@tXAKaI|fw}D"
      },
      "mass": 397.2804671450629,
      "monoisotopicMass": 397.07873487324,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 14
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Pdu": {
      "name": "3-methylpseudouridine monophosphate diradical 39U",
      "mf": "C10H13N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "κ",
      "ocl": {
        "value": "fncPK@OAaSbgIrtGc[pbxyDhhilheDiMFs`RuUUTsTuMDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@HoWtw@`lFC~NSU@"
      },
      "mass": 320.1929965859354,
      "monoisotopicMass": 320.04095238282997,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mri": {
      "name": "3-methyluridine monophosphate diradical 3U",
      "mf": "C10H13N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "δ",
      "ocl": {
        "value": "fncPK@I^aSbgIrtGc[pbxyDhhilheDiMFs`RuUUUSLuMDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@HoWtw@`lFC~NSU@"
      },
      "mass": 320.1929965859354,
      "monoisotopicMass": 320.04095238282997,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Acc": {
      "name": "N4-acetylcytidine monophosphate diradical 42C",
      "mf": "C11H14N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "M",
      "ocl": {
        "value": "fikpK@I^kBgENSghOFwaEqrIQQSYQJIRYiQg@ejjjjfYffhbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuPOxxSItuP"
      },
      "mass": 347.21837644817225,
      "monoisotopicMass": 347.05185141949,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Iws": {
      "name": "isowyosine monophosphate diradical 42G",
      "mf": "C14H16N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "⊇",
      "ocl": {
        "value": "ek`ZNL@IG@fnhJNEDla`OFspb\\\\bTTTvTRbTbSbRrXx|BjzfVjjjjiYjYjjdaBXPaLP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RStwQ@MD@RpQ_qcQSU@"
      },
      "mass": 397.2804671450629,
      "monoisotopicMass": 397.07873487324,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 14
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dmc": {
      "name": "N4,N4-dimethylcytidine monophosphate diradical 44C",
      "mf": "C11H16N3O7P",
      "kind": "NucleotideP",
      "oneLetter": "μ",
      "ocl": {
        "value": "fasqs@I^kBgENSdGc[pbxyDhhilheDiLuF\\BVjjjjYfZjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBGpcbpXBGtSItuPSU@H_Wtw@`lFDuPOxxlF@"
      },
      "mass": 333.23485303196554,
      "monoisotopicMass": 333.07258686438,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Adw": {
      "name": "7-aminocarboxypropyl-demethylwyosine monophosphate diradical 47G",
      "mf": "C17H21N6O9P",
      "kind": "NucleotideP",
      "oneLetter": "¥",
      "ocl": {
        "value": "elVVIL@IG@fnohJNEDlahTPOFspb\\\\bTTTvTRbTbSbRrrTtXx|BjzfVjjjjiYjYjjijdaBXPaLP@",
        "coordinates": "!B`MERc|@Y_]^DUH{_UMo_tXa}SXPTh{_w}GjXES[pAg_t]F@cm@Il@f@haTvuS[pAgPThQTbGvH@ha}_c~HGx@bGt"
      },
      "mass": 484.3578916656298,
      "monoisotopicMass": 484.1107632779601,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 17
      }, {
        "symbol": "H",
        "number": 21
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ncd": {
      "name": "N4-methylcytidine monophosphate diradical 4C",
      "mf": "C10H14N3O7P",
      "kind": "NucleotideP",
      "oneLetter": "ν",
      "ocl": {
        "value": "fncqs@I^kBgENSdGc[pbxyDhhilheDiLts`RuUUUSLsUDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuPKA`"
      },
      "mass": 319.2082356271187,
      "monoisotopicMass": 319.05693679992004,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dmw": {
      "name": "4-demethylwyosine monophosphate diradical 4G",
      "mf": "C13H14N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "†",
      "ocl": {
        "value": "fcis@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\RVYspZ}fnjjjjefifjiHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RStwQ@MD@RpQ_qcQ"
      },
      "mass": 383.253849740216,
      "monoisotopicMass": 383.06308480878,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mtu": {
      "name": "5-methoxyuridine monophosphate diradical 501U",
      "mf": "C10H13N2O9P",
      "kind": "NucleotideP",
      "oneLetter": "5",
      "ocl": {
        "value": "fasQK@I^aSbgIsUhOFwaEqrIQQSYQJIRYULxDmUUUTsMSTQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
      },
      "mass": 336.19240151025366,
      "monoisotopicMass": 336.03586700240004,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Uoa": {
      "name": "uridine 5-oxyacetic acid monophosphate diradical 502U",
      "mf": "C11H13N2O11P",
      "kind": "NucleotideP",
      "oneLetter": "V",
      "ocl": {
        "value": "fmgQk@I^aSbgIsUlu`|[^DWGHeEEMeDheIeUeF\\BVjjjjYfiijHbXaDr@@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{WHc|KB_W_Wx@_`@lIr\\SFBrHHc|_`BH_Xc|_`BH_P"
      },
      "mass": 380.2019472556255,
      "monoisotopicMass": 380.02569624154,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ume": {
      "name": "uridine 5-oxyacetic acid methyl ester monophosphate diradical 503U",
      "mf": "C12H15N2O11P",
      "kind": "NucleotideP",
      "oneLetter": "υ",
      "ocl": {
        "value": "fcwQk@I^aSbgIsUlu`|[^DWGHeEEMeDheIeUeLs`RuUUUSLuMMTQDqBId@@",
        "coordinates": "!BKAb@tURDM\\YpMAMpBYMcxc|KB]~@Ha}SXWHc|bOqMcx}RtDvH_Xa}bOrH@ha}_c~HHa}"
      },
      "mass": 394.2285646604723,
      "monoisotopicMass": 394.041346306,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hxc": {
      "name": "5-hydroxycytidine monophosphate diradical 50C",
      "mf": "C9H12N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "Ç",
      "ocl": {
        "value": "fncpK@I^[BgENSfhOFwaEqrIQQSYQJIRYUg@ejjjjfYfjHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
      },
      "mass": 321.1810231465902,
      "monoisotopicMass": 321.03620135502996,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hxu": {
      "name": "5-hydroxyuridine monophosphate diradical 50U",
      "mf": "C9H11N2O9P",
      "kind": "NucleotideP",
      "oneLetter": "∝",
      "ocl": {
        "value": "fncQK@I^aSbgIsUhOFwaEqrIQQSYQJIRYUg@ejjjjfYjZHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
      },
      "mass": 322.1657841054069,
      "monoisotopicMass": 322.02021693794,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Amu": {
      "name": "5-aminomethyluridine monophosphate diradical 510U",
      "mf": "C10H14N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "∪",
      "ocl": {
        "value": "faspK@I^{BgENSehOFwaEqrIQQSYQJIRYULxDmUUUTsMSTQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
      },
      "mass": 335.207640551437,
      "monoisotopicMass": 335.05185141949,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mau": {
      "name": "5-methylaminomethyluridine monophosphate diradical 511U",
      "mf": "C11H16N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "{",
      "ocl": {
        "value": "fikpK@I^{BgENSehOFwaEqrIQQSYQJIRYUYg@ejjjjfYjZhbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTBpX"
      },
      "mass": 349.2342579562838,
      "monoisotopicMass": 349.06750148395,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hmc": {
      "name": "5-hydroxymethylcytidine monophosphate diradical 51C",
      "mf": "C10H14N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "∅",
      "ocl": {
        "value": "faspK@I^[BgENSghOFwaEqrIQQSYQJIRYULxDmUUUTsLuTQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
      },
      "mass": 335.207640551437,
      "monoisotopicMass": 335.05185141949,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Cur": {
      "name": "5-carboxymethylaminomethyluridine monophosphate diradical 51U",
      "mf": "C12H16N3O10P",
      "kind": "NucleotideP",
      "oneLetter": "!",
      "ocl": {
        "value": "fcwpk@I^{BgENSej}`|[^DWGHeEEMeDheIeUdhs`RuUUUSLuMSTQDqBId@@",
        "coordinates": "!BKAb@tURDM\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@I~@Ha}"
      },
      "mass": 393.24380370165557,
      "monoisotopicMass": 393.05733072309,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Chr": {
      "name": "5-carboxyhydroxymethyluridine monophosphate diradical 520U",
      "mf": "C11H13N2O11P",
      "kind": "NucleotideP",
      "oneLetter": "≥",
      "ocl": {
        "value": "fmgQk@I^aSbgIrwlu`|[^DWGHeEEMeDheIeUCF\\BVjjjjYfiijHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tTuPOxxlF@"
      },
      "mass": 380.2019472556255,
      "monoisotopicMass": 380.02569624154,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mcu": {
      "name": "5-methoxycarbonylmethyluridine monophosphate diradical 521U",
      "mf": "C12H15N2O10P",
      "kind": "NucleotideP",
      "oneLetter": "1",
      "ocl": {
        "value": "fmgPk@I^aSbgIrt\\p^MoBKcdRbbfrbTRdrjtsNAKUUUULsTsUDQLPbY@@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{WHc|KB_W_Wx@_`@lIr\\SFBrH@h`B_`BH_WxbOrH_P"
      },
      "mass": 378.229159736154,
      "monoisotopicMass": 378.04643168643,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hme": {
      "name": "5-(carboxyhydroxymethyl)uridine methyl ester monophosphate diradical 522U",
      "mf": "C12H15N2O11P",
      "kind": "NucleotideP",
      "oneLetter": ",",
      "ocl": {
        "value": "fcwQk@I^aSbgIrwlu`|[^DWGHeEEMeDheIeUCLs`RuUUUSLuMMTQDqBId@@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{WHc|KB_W_Wx@_`@lIr\\SFBrHHc|_`A~@Ha}_c~H@ha}"
      },
      "mass": 394.2285646604723,
      "monoisotopicMass": 394.041346306,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Cxu": {
      "name": "5-carboxymethyluridine monophosphate diradical 52U",
      "mf": "C11H13N2O10P",
      "kind": "NucleotideP",
      "oneLetter": "◊",
      "ocl": {
        "value": "fe{Pk@I^aSbgIrt\\p^MoBKcdRbbfrbTRdrjtYpIZjjjifZfZbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTC~NKA`"
      },
      "mass": 364.2025423313072,
      "monoisotopicMass": 364.03078162197,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hmu": {
      "name": "5-carbamoylhydroxymethyluridine monophosphate diradical 531U",
      "mf": "C11H14N3O10P",
      "kind": "NucleotideP",
      "oneLetter": "r",
      "ocl": {
        "value": "fmgpk@I^WBgENSeoY`|[^DWGHeEEMeDheIeUCF\\BVjjjjYfiijHbXaDr@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tTuPOxxlF@"
      },
      "mass": 379.21718629680873,
      "monoisotopicMass": 379.04168065863,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ymu": {
      "name": "5-carbamoylmethyluridine monophosphate diradical 53U",
      "mf": "C11H14N3O9P",
      "kind": "NucleotideP",
      "oneLetter": "&",
      "ocl": {
        "value": "fe{qK@I^gBgENSehp^MoBKcdRbbfrbTRdrjtYpIZjjjifZfZbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTC~NKA`"
      },
      "mass": 363.2177813724905,
      "monoisotopicMass": 363.04676603906006,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ttu": {
      "name": "5-taurinomethyluridine monophosphate diradical 54U",
      "mf": "C12H18N3O11PS",
      "kind": "NucleotideP",
      "oneLetter": "Ê",
      "ocl": {
        "value": "fgqh`I^{BgENSenswAxv|HnJpcHeEEMeDheIeUdeHs`RuUUUSLuMTmQDSDHfP@",
        "coordinates": "!BKAb@tURD@m\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@JH__rH_]^H_P"
      },
      "mass": 443.32387754021244,
      "monoisotopicMass": 443.03996658152005,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Cmu": {
      "name": "5-cyanomethyluridine monophosphate diradical 55U",
      "mf": "C11H12N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "Ѷ",
      "ocl": {
        "value": "fikpK@I^GBgENSehOFwaEqrIQQSYQJIRYUYg@ejjjjfYj[hbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tPCQ"
      },
      "mass": 345.20249494006066,
      "monoisotopicMass": 345.03620135502996,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Pyu": {
      "name": "5-(isopentenylaminomethyl)uridine monophosphate diradical 583U",
      "mf": "C15H22N3O8P",
      "kind": "NucleotideP",
      "oneLetter": "¾",
      "ocl": {
        "value": "fkopK@I^{BgENSehOFwaEqrIQQSYQJIRYUYIQg@ejjjjfYjZfjHbXaDr@@",
        "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{W@h`BKB_W_Wx@_`@lIr\\SFBrH@h`B_`BH_Xc|bGvH@gx@bGt"
      },
      "mass": 403.32484606755946,
      "monoisotopicMass": 403.11445167733,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 22
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mdu": {
      "name": "5-methyldihydrouridine monophosphate diradical 58U",
      "mf": "C10H15N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "ρ",
      "ocl": {
        "value": "fncPK@I^aSbgIrtGc[pbxyDhhilheDiLjs`RuUUUSTuMDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
      },
      "mass": 322.20887809404695,
      "monoisotopicMass": 322.05660244729,
      "unsaturation": 8,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mcd": {
      "name": "5-methylcytidine monophosphate diradical 5C",
      "mf": "C10H14N3O7P",
      "kind": "NucleotideP",
      "oneLetter": "?",
      "ocl": {
        "value": "fncqs@I^[BgENSdGc[pbxyDhhilheDiLjs`RuUUUSLsUDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
      },
      "mass": 319.2082356271187,
      "monoisotopicMass": 319.05693679992004,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hia": {
      "name": "N6-(cis-hydroxyisopentenyl)adenosine monophosphate diradical 60A",
      "mf": "C15H20N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "`",
      "ocl": {
        "value": "eg`ZNL@IG@fnhJNEDlk`OFspb\\\\bTTTvTRbTbSVRTSGG`USUUUUTCLATuTDHSBDIbPSH",
        "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@b@JH@ha}bOrH_Wxb@JH_P"
      },
      "mass": 413.3229660580212,
      "monoisotopicMass": 413.11003500216003,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 20
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mta": {
      "name": "2-methylthio-N6-methyladenosine monophosphate diradical 621A",
      "mf": "C12H16N5O6PS",
      "kind": "NucleotideP",
      "oneLetter": "∞",
      "ocl": {
        "value": "fmwhp`CQstZLDxipEfGa[qZDYEIlheDdhXdmDmKR\\u{MUUUU@aEUAFPTdmH@",
        "coordinates": "!BBGw|B@a}_S\\H@a}TEJNOuP{Ntm@fPBN[~iRSpHUCneXDBYTEITAEPDiVA@fTBYU@Sj[p"
      },
      "mass": 389.3243778334011,
      "monoisotopicMass": 389.05589142807,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Tca": {
      "name": "N6-threonylcarbamoyladenosine monophosphate diradical 62A",
      "mf": "C15H19N6O10P",
      "kind": "NucleotideP",
      "oneLetter": "6",
      "ocl": {
        "value": "edRVEL@IG@fnehJNEDligo`POFspb\\\\bTTTvTRbTbSVTrbbcGG`USUUUUTCLASUMUABDpaBX`@",
        "coordinates": "!BzfC@IeKPaDn}bHCQbOsQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@b@JH@ha}_c~H@ha}_c~H@ha}uwu~@Ha}"
      },
      "mass": 474.31994328836606,
      "monoisotopicMass": 474.09002783307,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 19
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hva": {
      "name": "N6-hydroxynorvalylcarbamoyladenosine monophosphate diradical 63A",
      "mf": "C16H21N6O10P",
      "kind": "NucleotideP",
      "oneLetter": "√",
      "ocl": {
        "value": "elZVIB@IG@fnehJNDligo`POEQql|HgGHeEEMeDheHdueLhhiVNO@jfjjjjhFXBfjZj`aBXPaLP@",
        "coordinates": "!BpBYTvxBNFY|bEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~HH`BbGvH_Xc|_`BH_Xc|_`BH_]_|bOq~Oxc|bGt"
      },
      "mass": 488.34656069321284,
      "monoisotopicMass": 488.10567789753003,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 16
      }, {
        "symbol": "H",
        "number": 21
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Aya": {
      "name": "N6-acetyladenosine monophosphate diradical 64A",
      "mf": "C12H14N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "⇓",
      "ocl": {
        "value": "fmwis@INBwlJ\\TgLp^MoBKcdRbbfrbTRdRZrcN^CUmUUUTCLASTDQLPbY@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}RIqOQ@@"
      },
      "mass": 371.2431138434808,
      "monoisotopicMass": 371.06308480878,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Gca": {
      "name": "N6-glycinylcarbamoyladenosine monophosphate diradical 65A",
      "mf": "C13H15N6O9P",
      "kind": "NucleotideP",
      "oneLetter": "≡",
      "ocl": {
        "value": "eohVIL@IG@fnehJNEDlikg`OFspb\\\\bTTTvTRbTbSVTrTXx|BjZjjjj`Y`JZfhHPfDHSD@@",
        "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@bOrHHa}_c~H@ha}bOq~@Ha}"
      },
      "mass": 430.2673035543541,
      "monoisotopicMass": 430.06381308458,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 13
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Tya": {
      "name": "N6-methyl-N6-threonylcarbamoyladenosinemonophosphate diradical 662A",
      "mf": "C16H21N6O10P",
      "kind": "NucleotideP",
      "oneLetter": "E",
      "ocl": {
        "value": "elZVEL@IG@fnmhJNEDleo`XPOFspb\\\\bTTTvTRbTbSVbaTTTXx|BjZjjjj`Y`JfjZjBDIaBDq@@",
        "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@bOrHHa}_`A~Ox`BbGu~Ox`BbGwW_Wx@bGt"
      },
      "mass": 488.34656069321284,
      "monoisotopicMass": 488.10567789753003,
      "unsaturation": 18,
      "elements": [{
        "symbol": "C",
        "number": 16
      }, {
        "symbol": "H",
        "number": 21
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Nna": {
      "name": "N6,N6-dimethyladenosine monophosphate diradical 66A",
      "mf": "C12H16N5O6P",
      "kind": "NucleotideP",
      "oneLetter": "ζ",
      "ocl": {
        "value": "feghs@INBwlJ\\TgHOFwaEqrIQQSYQJIRIMZLyxMVuUUUPLpEUADSDHfP@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}RFBp"
      },
      "mass": 357.2595904272741,
      "monoisotopicMass": 357.08382025367,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Fya": {
      "name": "N6-formyladenosine monophosphate diradical 67A",
      "mf": "C11H12N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "Ϩ",
      "ocl": {
        "value": "fegis@INBwlJ\\TgLp^MoBKcdRbbfrbTRdRZrYspZmjjjj`Y`JZBHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}RtP@"
      },
      "mass": 357.216496438634,
      "monoisotopicMass": 357.04743474432,
      "unsaturation": 16,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Hma": {
      "name": "N6-hydroxymethyladenosine monophosphate diradical 68A",
      "mf": "C11H14N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "Ϫ",
      "ocl": {
        "value": "fegis@INBwlJ\\TgLp^MoBKcdRbbfrbTRdRZrYspZmjjjj`Y`JjBHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}RtP@"
      },
      "mass": 359.23237794674554,
      "monoisotopicMass": 359.06308480878,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Cca": {
      "name": "cyclic N6-threonylcarbamoyladenosine monophosphate diradical 69A",
      "mf": "C15H17N6O9P",
      "kind": "NucleotideP",
      "oneLetter": "e",
      "ocl": {
        "value": "ehRVIL@IG@fnehJNEDliko`OFspb\\\\bTTTvTRbTbSVTRRtXx|BjZvNjjjj`Y`IjfjbHPfDHSD`z`",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_IorHbGtgD}F@RxRH_WwW@hbOTh}RtXCQ`A`l_`A`iVCjKAcjX@A~@h`Bup"
      },
      "mass": 456.30465685593623,
      "monoisotopicMass": 456.07946314904,
      "unsaturation": 20,
      "elements": [{
        "symbol": "C",
        "number": 15
      }, {
        "symbol": "H",
        "number": 17
      }, {
        "symbol": "N",
        "number": 6
      }, {
        "symbol": "O",
        "number": 9
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Fcy": {
      "name": "5-formylcytidine monophosphate diradical71C",
      "mf": "C10H12N3O8P",
      "kind": "NucleotideP",
      "oneLetter": ">",
      "ocl": {
        "value": "faspK@I^[BgENSghOFwaEqrIQQSYQJIRYULxDmUUUTsLttQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
      },
      "mass": 333.1917590433254,
      "monoisotopicMass": 333.03620135502996,
      "unsaturation": 12,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 12
      }, {
        "symbol": "N",
        "number": 3
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Tur": {
      "name": "4-thiouridine monophosphate diradical 74U",
      "mf": "C9H11N2O7PS",
      "kind": "NucleotideP",
      "oneLetter": "4",
      "ocl": {
        "value": "ff}Qp`I^aSbgIrCqmxQ\\ZaFQJJJ[JIQJSMg@ejjjjfYihbIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
      },
      "mass": 322.2317616628973,
      "monoisotopicMass": 322.0024588732,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Meg": {
      "name": "7-methylguanosine monophosphate diradical 7G",
      "mf": "C11H15N5O7P",
      "kind": "NucleotideP",
      "oneLetter": "7",
      "ocl": {
        "value": "fegisDINCt\\J\\TgLp^MoBKbF\\bTTTvTRbTbRlSN^CWmUUUUKLuSTQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StP@"
      },
      "mass": 360.2403187008013,
      "monoisotopicMass": 360.07090984101,
      "unsaturation": 13,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mea": {
      "name": "8-methyladenosine monophosphate diradical 8A",
      "mf": "C11H14N5O6P",
      "kind": "NucleotideP",
      "oneLetter": "â",
      "ocl": {
        "value": "fi{hs@INCt\\J\\UdhOFw`eqrIQQSYQJJJQKigOA[vjjjjAi`J`bIbDSH@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpP@c`a}_S_|BD}RSuKQ@MD@"
      },
      "mass": 343.2329730224273,
      "monoisotopicMass": 343.06817018921,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 14
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 6
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Dhu": {
      "name": "dihydrouridine monophosphate diradical 8U",
      "mf": "C9H13N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "D",
      "ocl": {
        "value": "ff}PK@I^aSbgIsTGc[pbxyDhhilheDiLv\\BVjjjjZffbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
      },
      "mass": 308.1822606892002,
      "monoisotopicMass": 308.04095238282997,
      "unsaturation": 8,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Ins": {
      "name": "inosine monophosphate diradical 9A",
      "mf": "C10H11N4O7P",
      "kind": "NucleotideP",
      "oneLetter": "I",
      "ocl": {
        "value": "fakIs@INBvENJSghOFwaEqrIQQSYQJIRIMLyxMVuUUUTlsSTQDqBId@@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@@"
      },
      "mass": 330.1911165763972,
      "monoisotopicMass": 330.03653570766,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 4
      }, {
        "symbol": "O",
        "number": 7
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Pis": {
      "name": "pseudouridine monophosphate diradical 9U",
      "mf": "C9H11N2O8P",
      "kind": "NucleotideP",
      "oneLetter": "P",
      "ocl": {
        "value": "ff}PK@OAaSbgIsTGc[pbxyDhhilheDiLv\\BVjjjfZffbHfHQL`@",
        "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
      },
      "mass": 306.1663791810886,
      "monoisotopicMass": 306.02530231837,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 9
      }, {
        "symbol": "H",
        "number": 11
      }, {
        "symbol": "N",
        "number": 2
      }, {
        "symbol": "O",
        "number": 8
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Pqb": {
      "name": "preQ0base 100G diradical (base)",
      "mf": "C7H5N5O",
      "kind": "Nucleotide",
      "oneLetter": "ψ",
      "ocl": {
        "value": "dk^h@DxYLLbbTTRekiujYj^`@",
        "coordinates": "!B|Gwp_Gy|Gwp_[lk_gp_Ag_wrYRs}|f"
      },
      "mass": 175.1477760289729,
      "monoisotopicMass": 175.04940980287,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 5
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Pqg": {
      "name": "preQ1base 101G diradical (base)",
      "mf": "C7H9N5O",
      "kind": "Nucleotide",
      "oneLetter": "∇",
      "ocl": {
        "value": "dk^h@DxYLLbbTTRckiUjYij`@",
        "coordinates": "!BWyfe[tlDWye_fXx@RpRe[wtHSuHH@a}"
      },
      "mass": 179.179539045196,
      "monoisotopicMass": 179.08070993179,
      "unsaturation": 10,
      "elements": [{
        "symbol": "C",
        "number": 7
      }, {
        "symbol": "H",
        "number": 9
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 1
      }]
    },
    "Qba": {
      "name": "Qbase 10G diradical (base)",
      "mf": "C12H15N5O3",
      "kind": "Nucleotide",
      "oneLetter": "∴",
      "ocl": {
        "value": "fbmi`@D\\EHpHyrJIQQJMJIPtyIPTmSMMUMUP@@",
        "coordinates": "!BRpQ_f^i`RpQKAEARzfA_f_pHtP@H_Pc|BGuPThxUCl{RtBYTd|"
      },
      "mass": 277.27967290184347,
      "monoisotopicMass": 277.11748936431,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 15
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 3
      }]
    },
    "Dgc": {
      "name": "N2,7-dimethylguanosine cap (cap DMG) diradical 279553N",
      "mf": "C12H18N5O11P2",
      "kind": "Nucleotide",
      "oneLetter": "®",
      "ocl": {
        "value": "e`TZMBHIG@aihJNEHdlemck`OFspz|OgDJ\\bTTTvTRbTbRvbtfKGG`UPuUUUUJtuTmUTPaLHPfH@@",
        "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPbOr_IorHbGtgD}F@RxS|uxc|_]^OTh}RIlBH_]F@IqOQ`@A~_c|bH}RbGt"
      },
      "mass": 470.24625855539705,
      "monoisotopicMass": 470.04780541440005,
      "unsaturation": 13,
      "elements": [{
        "symbol": "C",
        "number": 12
      }, {
        "symbol": "H",
        "number": 18
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Dpa": {
      "name": "5′-(3′-dephosphoacetyl-CoA) diradical 4155N",
      "mf": "C23H35N7O16P3S",
      "kind": "Nucleotide",
      "oneLetter": "♣",
      "ocl": {
        "value": "elz~@jDCHlemnSTLBAEKBjfckgbV]XpEfCpB|IoCtHZy{lbdvbbfrbTRdRNRdnTbefRTrRTdTRrFVfjjjj`V`bZjjfjZjZ`bbLSaRP@",
        "coordinates": "!BvtmKaMmKUMlfgto[tDw_cosWt]~H@dvObGv_F_sWbOpgKMG_R}m}bHa}HbOSX}M_cQw}G_OwzH_[wW_c~H_Wx@G{|bM]}bGvHGxbGu~Oxa}bOq~Oxa}_c~H_WxuwvH_P"
      },
      "mass": 790.5483266874629,
      "monoisotopicMass": 790.1073852418399,
      "unsaturation": 21,
      "elements": [{
        "symbol": "C",
        "number": 23
      }, {
        "symbol": "H",
        "number": 35
      }, {
        "symbol": "N",
        "number": 7
      }, {
        "symbol": "O",
        "number": 16
      }, {
        "symbol": "P",
        "number": 3
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Dpm": {
      "name": "5′-(3′-dephosphomalonyl-CoA) diradical 4255N",
      "mf": "C24H35N7O18P3S",
      "kind": "Nucleotide",
      "oneLetter": "♥",
      "ocl": {
        "value": "efq~DjDCHlemnSTLBAEKBjfckgbV]XrzpEfCpB|IoCtHZy{lbdvbbfrbTRdRNRdnTbefRTrRTrdbbVPrtuUUUTBtDSUUTuSUSSTDTQb\\JR@@",
        "coordinates": "!BIlB_Ib[@pAe`zni`FALSF@A~FBq~OrpXbGveX@A~_c~OTa`lzf@_ha}_]_Q`MF@bOpXKA`loXbH__rHb@JHoX`B@m]}uwx@bGu~Ox`BbKvH@ha}_c~H@hb}b@JH_Xc|_`BH_X`B_`BHoP"
      },
      "mass": 834.5578724328346,
      "monoisotopicMass": 834.0972144809799,
      "unsaturation": 23,
      "elements": [{
        "symbol": "C",
        "number": 24
      }, {
        "symbol": "H",
        "number": 35
      }, {
        "symbol": "N",
        "number": 7
      }, {
        "symbol": "O",
        "number": 18
      }, {
        "symbol": "P",
        "number": 3
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Dsc": {
      "name": "5′-(3′-dephosphosuccinyl-CoA) radical 4355N",
      "mf": "C25H37N7O18P3S",
      "kind": "Nucleotide",
      "oneLetter": "♦",
      "ocl": {
        "value": "eny~DjDCHlemnSTLBAEKBjfckgbV]XzvpOFCpB|IoCtHZy{lbdvbbfrbTRdRNRdnTbefRTrRTrTdTRrFVfjjjj`V`bZjjfjZjZfhHhcDxTd@@",
        "coordinates": "!B[~kjXFjiV[Ry|fcm}MtGwWctvH_]Q_c}KaGwWbGvN`H}MgrX@_gx@h`gKB\\lbGvOSX}M@m^H@gwWbGvH@ha}_Xc|bGxb@I~@Ha}b@JH_X`B_`BH_X`BbGvH@ha}_c~H@ha}b@I~@Ha}"
      },
      "mass": 848.5844898376815,
      "monoisotopicMass": 848.11286454544,
      "unsaturation": 23,
      "elements": [{
        "symbol": "C",
        "number": 25
      }, {
        "symbol": "H",
        "number": 37
      }, {
        "symbol": "N",
        "number": 7
      }, {
        "symbol": "O",
        "number": 18
      }, {
        "symbol": "P",
        "number": 3
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Dpc": {
      "name": "5′-(3′-dephospho-CoA) radical 455N",
      "mf": "C21H32N7O13P2S",
      "kind": "Nucleotide",
      "oneLetter": "♠",
      "ocl": {
        "value": "ek_^KBDIG@nabYXJNEHdliemh\\QPEfspZ|CPcKmnrIQQSYQJIRIGIRWJQRsIJYIccpJkjjjjjAZBIjjjZijjBDIaBDq@@",
        "coordinates": "!B[zW[UI|YchAMc{vHcuJH@m~NbGuKvwvHb@JNwx}Rgqe}bHa}@h`gDr\\Sb@JOTh}R@m]~@@A~b@I~@H`B_X`_hb}_`CW@h`B_`BH@gx@upJH@gx@b@I~@@"
      },
      "mass": 684.5310558604504,
      "monoisotopicMass": 684.1254042880199,
      "unsaturation": 19,
      "elements": [{
        "symbol": "C",
        "number": 21
      }, {
        "symbol": "H",
        "number": 32
      }, {
        "symbol": "N",
        "number": 7
      }, {
        "symbol": "O",
        "number": 13
      }, {
        "symbol": "P",
        "number": 2
      }, {
        "symbol": "S",
        "number": 1
      }]
    },
    "Dpe": {
      "name": "5′-diphosphate end 552N",
      "mf": "O3P",
      "kind": "Nucleotide",
      "oneLetter": "ϒ",
      "ocl": {
        "value": "gJQdebGF^Dx|duK@@",
        "coordinates": "!BbOq~@GxbGt"
      },
      "mass": 78.97197677137483,
      "monoisotopicMass": 78.95850585713,
      "unsaturation": 1,
      "elements": [{
        "symbol": "O",
        "number": 3
      }, {
        "symbol": "P",
        "number": 1
      }]
    },
    "Mgc": {
      "name": "7-methylguanosine cap (cap 0) diradical 79553N",
      "mf": "C11H16N5O11P2",
      "kind": "Nucleotide",
      "oneLetter": "©",
      "ocl": {
        "value": "eohZMBHIG@aihJNEHdlemck`OFspz|GgDJ\\bTTTvTRbTbRvbtcXx|BjFjjjjiVfjejjHPfDHSD@@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_I`JHbGtgD}F@RxPBux`B_]^OTh}RIlBH_]F@IqOQ`@A~_c|BbHa}"
      },
      "mass": 456.2196411505502,
      "monoisotopicMass": 456.03215534994,
      "unsaturation": 13,
      "elements": [{
        "symbol": "C",
        "number": 11
      }, {
        "symbol": "H",
        "number": 16
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 11
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Gyy": {
      "name": "guanylylated 5′ end (cap G) diradical 9553N",
      "mf": "C10H13N5O10P2",
      "kind": "Nucleotide",
      "oneLetter": "ϑ",
      "ocl": {
        "value": "fkhh`INCt\\J\\UENY{NCqmxM|EnNQJJJ[JIQJQHzIRLyxM^uUUUTkSULuQDSDHfP@",
        "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_I`JHbGtgD}F@RxPBux`B_]^OTh}R_`CQ`B\\StXA~@C}~@Gx"
      },
      "mass": 425.1856780673293,
      "monoisotopicMass": 425.01376563368,
      "unsaturation": 14,
      "elements": [{
        "symbol": "C",
        "number": 10
      }, {
        "symbol": "H",
        "number": 13
      }, {
        "symbol": "N",
        "number": 5
      }, {
        "symbol": "O",
        "number": 10
      }, {
        "symbol": "P",
        "number": 2
      }]
    },
    "Furp": {
      "name": "furan phosphate radical",
      "mf": "C5H6O4P",
      "kind": "RNAp",
      "oneLetter": "⬠",
      "ocl": {
        "value": "dmtBPDpnAYcpRZ}eeYjii@@",
        "coordinates": "!B]w|Mw\\B_S]wW\\BtP@oKS~frpP"
      },
      "mass": 161.072705703704,
      "monoisotopicMass": 161.00037067008,
      "unsaturation": 5,
      "elements": [{
        "symbol": "C",
        "number": 5
      }, {
        "symbol": "H",
        "number": 6
      }, {
        "symbol": "O",
        "number": 4
      }, {
        "symbol": "P",
        "number": 1
      }]
    }
  };

  const elements$2 = src$j.elementsAndStableIsotopesObject;

  function getIsotopeRatioInfo(value) {
    let result = {
      mass: 0,
      monoisotopicMass: 0
    };
    let element = elements$2[value.atom];
    if (!element) throw new Error(`Element not found: ${value.atom}`);
    let isotopesArray = element.isotopes;
    let ratios = normalize$4(value.ratio);
    let max = Math.max(...ratios);

    if (ratios.length > isotopesArray.length) {
      throw new Error(`the number of specified ratios is bigger that the number of stable isotopes: ${value.atom}`);
    }

    for (let i = 0; i < ratios.length; i++) {
      result.mass += ratios[i] * isotopesArray[i].mass;

      if (max === ratios[i] && result.monoisotopicMass === 0) {
        result.monoisotopicMass = isotopesArray[i].mass;
      }
    }

    return result;
  }

  function normalize$4(array) {
    let sum = array.reduce((prev, current) => prev + current, 0);
    return array.map(a => a / sum);
  }

  var getIsotopeRatioInfo_1 = getIsotopeRatioInfo;

  const isotopes = {};
  Object.keys(elementsAndIsotopesObject_1).forEach(key => {
    let e = elementsAndIsotopesObject_1[key];
    e.isotopes.forEach(i => {
      isotopes[i.nominal + key] = {
        abundance: i.abundance,
        mass: i.mass
      };
    });
  });
  var getIsotopesObject = isotopes;

  const elements$1 = src$j.elementsObject;
  /**
   *
   * @param {*} parts
   * @param {*} [options={}]
   */

  var getEA = function getEA(parts) {
    let results = {};

    for (let part of parts) {
      for (let line of part) {
        switch (line.kind) {
          case Kind.ISOTOPE:
            {
              let isotope = getIsotopesObject[line.value.isotope + line.value.atom];

              if (!isotope) {
                throw new Error(`Unknown isotope: ${line.value.isotope}${line.value.atom}`);
              }

              addMass(results, line.value.atom, isotope.mass * line.multiplier);
              break;
            }

          case Kind.ISOTOPE_RATIO:
            {
              let isotopeRatioInfo = getIsotopeRatioInfo_1(line.value);
              addMass(results, line.value.atom, isotopeRatioInfo.mass * line.multiplier);
              break;
            }

          case Kind.ATOM:
            {
              let element = elements$1[line.value];

              if (!element) {
                element = groupsObject[line.value];
                if (!element) throw Error(`Unknown element: ${line.value}`); // need to explode group ????
              }

              addMass(results, line.value, element.mass * line.multiplier);
              break;
            }

          case Kind.CHARGE:
            break;

          default:
            throw new Error('partToMF unhandled Kind: ', line.kind);
        }
      }
    }

    let eas = [];
    let sum = 0;

    for (let key in results) {
      sum += results[key];
      eas.push({
        element: key,
        mass: results[key]
      });
    }

    eas.forEach(ea => {
      ea.ratio = ea.mass / sum;
    });
    return eas;
  };

  function addMass(results, atom, mass) {
    if (!results[atom]) results[atom] = 0;
    results[atom] += mass;
  }

  var unsaturationsObject = {
    O: 0,
    N: 1,
    H: -1,
    Na: -1,
    K: -1,
    Li: -1,
    Ca: -2,
    C: 2,
    F: -1,
    Si: 2,
    Cl: -1,
    Br: -1,
    I: -1,
    S: 0,
    P: 1
  };

  /**
   * Convert a MF part to an array of atoms
   * This procedure will suppress the isotopes !
   * This is mainly used to make queries
   */


  var partToAtoms = function partToAtoms(part) {
    let atoms = {};

    for (let line of part) {
      switch (line.kind) {
        case Kind.ISOTOPE:
          if (!atoms[line.value.atom]) atoms[line.value.atom] = 0;
          atoms[line.value.atom] += line.multiplier;
          break;

        case Kind.ISOTOPE_RATIO:
          if (!atoms[line.value.atom]) atoms[line.value.atom] = 0;
          atoms[line.value.atom] += line.multiplier;
          break;

        case Kind.ATOM:
          if (!atoms[line.value]) atoms[line.value] = 0;
          atoms[line.value] += line.multiplier;
          break;

        case Kind.CHARGE:
          break;

        case Kind.ANCHOR:
          break;

        default:
          throw new Error('partToMF unhandled Kind: ', line.kind);
      }
    }

    return atoms;
  };

  var partToMF = function partToMF(part, options = {}) {
    let mf = [];

    for (let line of part) {
      switch (line.kind) {
        case Kind.ISOTOPE:
          if (line.multiplier !== 0) {
            mf.push(`[${line.value.isotope}${line.value.atom}]${line.multiplier !== 1 ? line.multiplier : ''}`);
          }

          break;

        case Kind.ISOTOPE_RATIO:
          if (line.multiplier !== 0) {
            mf.push(`${line.value.atom}{${line.value.ratio.join(',')}}${line.multiplier !== 1 ? line.multiplier : ''}`);
          }

          break;

        case Kind.ATOM:
          if (line.multiplier !== 0) {
            mf.push(line.value + (line.multiplier !== 1 ? line.multiplier : ''));
          }

          break;

        case Kind.CHARGE:
          if (line.value === 0 || options.neutral) break;
          mf.push(`(${line.value > 0 ? `+${line.value}` : line.value})`);
          break;
      }
    }

    return mf.join('');
  };

  const {
    ELECTRON_MASS: ELECTRON_MASS$5
  } = constants;
  /**
   *
   * @param {*} parts
   * @param {*} [options={}]
   */

  var getInfo$1 = function getInfo(parts, options = {}) {
    let {
      customUnsaturations = {}
    } = options;
    if (parts.length === 0) return {};

    if (parts.length === 1) {
      return getProcessedPart$1(parts[0], customUnsaturations);
    }

    let result = {
      parts: []
    };

    for (let part of parts) {
      result.parts.push(getProcessedPart$1(part, customUnsaturations));
    }

    result.monoisotopicMass = 0;
    result.mass = 0;
    result.charge = 0;
    result.mf = result.parts.map(a => a.mf).join('.');
    result.parts.forEach(a => {
      result.mass += a.mass;
      result.monoisotopicMass += a.monoisotopicMass;
      result.charge += a.charge;
    });
    return result;
  };

  function getProcessedPart$1(part, customUnsaturations) {
    let currentPart = {
      mass: 0,
      monoisotopicMass: 0,
      charge: 0,
      mf: '',
      atoms: partToAtoms(part)
    };
    let unsaturation = 0;
    let validUnsaturation = true;
    currentPart.mf = partToMF(part);

    for (let line of part) {
      let currentElement = '';

      switch (line.kind) {
        case Kind.ATOM:
          {
            currentElement = line.value;
            let element = elementsAndIsotopesObject_1[line.value]; // todo should we have a kind GROUP ?

            if (!element) {
              element = groupsObject[line.value];
              if (!element) throw Error(`Unknown element: ${line.value}`);

              if (!customUnsaturations[line.value]) {
                customUnsaturations[line.value] = element.unsaturation;
              }
            }

            if (!element) throw new Error(`Unknown element: ${line.value}`);
            currentPart.monoisotopicMass += element.monoisotopicMass * line.multiplier;
            currentPart.mass += element.mass * line.multiplier;
            break;
          }

        case Kind.ISOTOPE:
          {
            currentElement = line.value.atom;
            let isotope = getIsotopesObject[line.value.isotope + line.value.atom];

            if (!isotope) {
              throw new Error(`Unknown isotope: ${line.value.isotope}${line.value.atom}`);
            }

            currentPart.monoisotopicMass += isotope.mass * line.multiplier;
            currentPart.mass += isotope.mass * line.multiplier;
            break;
          }

        case Kind.ISOTOPE_RATIO:
          {
            currentElement = line.value.atom;
            let isotopeRatioInfo = getIsotopeRatioInfo_1(line.value);
            currentPart.monoisotopicMass += isotopeRatioInfo.monoisotopicMass * line.multiplier;
            currentPart.mass += isotopeRatioInfo.mass * line.multiplier;
            break;
          }

        case Kind.CHARGE:
          currentPart.charge = line.value;

          if (validUnsaturation) {
            unsaturation -= line.value;
          }

          break;

        default:
          throw new Error('Unimplemented Kind in getInfo', line.kind);
      }

      if (currentElement) {
        if (customUnsaturations[currentElement] !== undefined) {
          unsaturation += customUnsaturations[currentElement] * line.multiplier;
        } else if (unsaturationsObject[currentElement] !== undefined) {
          unsaturation += unsaturationsObject[currentElement] * line.multiplier;
        } else {
          validUnsaturation = false;
        }
      }
    } // need to calculate the observedMonoisotopicMass


    if (currentPart.charge) {
      currentPart.observedMonoisotopicMass = (currentPart.monoisotopicMass - currentPart.charge * ELECTRON_MASS$5) / Math.abs(currentPart.charge);
    }

    if (validUnsaturation) {
      currentPart.unsaturation = unsaturation / 2 + 1;
    }

    return currentPart;
  }

  /**
   *
   * @param {*} parts
   * @param {*} options
   */


  var getIsotopesInfo = function getIsotopesInfo(parts) {
    if (parts.length === 0) return [];

    if (parts.length > 1) {
      throw new Error('getIsotopesInfo can not be applied on multipart MF');
    }

    return getProcessedPart(parts[0]);
  };

  function getProcessedPart(part) {
    let result = {
      charge: 0,
      isotopes: []
    };

    for (let line of part) {
      switch (line.kind) {
        case Kind.ISOTOPE:
          {
            let isotope = getIsotopesObject[line.value.isotope + line.value.atom];

            if (!isotope) {
              throw Error('unknown isotope:', line.value.atom, line.value.isotope);
            }

            result.isotopes.push({
              atom: `[${line.value.isotope}${line.value.atom}]`,
              number: line.multiplier,
              distribution: [{
                x: isotope.mass,
                y: 1
              }]
            });
            break;
          }

        case Kind.ISOTOPE_RATIO:
          {
            let element = elementsAndStableIsotopesObject_1[line.value.atom];
            if (!element) throw new Error('unknown element:', line.value);
            let distribution = getDistribution(element.isotopes, line.value.ratio);
            result.isotopes.push({
              atom: `${line.value.atom}{${line.value.ratio.join(',')}}`,
              number: line.multiplier,
              distribution
            });
          }
          break;

        case Kind.ATOM:
          {
            let element = elementsAndStableIsotopesObject_1[line.value];
            if (!element) throw new Error('unknown element:', line.value);
            result.isotopes.push({
              atom: line.value,
              number: line.multiplier,
              distribution: element.isotopes.map(e => ({
                x: e.mass,
                y: e.abundance
              }))
            });
            break;
          }

        case Kind.CHARGE:
          result.charge += line.value;
          break;

        default:
          throw new Error('partToMF unhandled Kind: ', line.kind);
      }
    }

    return result;
  }

  function getDistribution(isotopesArray, ratio) {
    let ratios = normalize$3(ratio);
    let result = [];

    if (ratios.length > isotopesArray.length) {
      throw new Error(`the number of specified ratios is bigger that the number of stable isotopes: ${getIsotopesObject}`);
    }

    for (let i = 0; i < ratios.length; i++) {
      result.push({
        x: isotopesArray[i].mass,
        y: ratios[i]
      });
    }

    return result;
  }

  function normalize$3(array) {
    let sum = array.reduce((prev, current) => prev + current, 0);
    return array.map(a => a / sum);
  }

  /**
   * Converts an array of mf elements to an array of formatting information
   * @param {Array<Object>} result of the parse method
   */


  var partsToDisplay = function partsToDisplay(parts) {
    let lines = [];

    for (let part of parts) {
      if (lines.length > 0) lines.push({
        kind: Kind.SALT,
        value: '•'
      });

      for (let partLine of part) {
        lines.push(partLine);

        if (partLine.multiplier) {
          lines.push({
            kind: Kind.MULTIPLIER,
            value: partLine.multiplier
          });
        }
      }
    }

    return toDisplay(lines);
  };

  var partsToMF = function partsToMF(parts, options) {
    let mf = [];

    for (let part of parts) {
      mf.push(partToMF(part, options));
    }

    return mf.join(' . ');
  };

  function atomSorter(a, b) {
    if (a === b) return 0;
    if (a === 'C') return -1;
    if (b === 'C') return 1;
    if (a === 'H') return -1;
    if (b === 'H') return 1;
    if (a < b) return -1;
    return 1;
  }

  var src$i = atomSorter;

  /**
   *
   * @param {*} lines
   * @param {object} [options={}]
   * @param {boolean} [options.expand=true] - Should we expand the groups
   */


  var toParts = function toParts(lines, options = {}) {
    const {
      expand: shouldExpandGroups = true
    } = options;
    let parts = [];
    let currentPart = createNewPart();
    let previousKind = Kind.BEGIN;
    parts.push(currentPart);

    for (let line of lines) {
      switch (line.kind) {
        case Kind.ATOM:
        case Kind.ISOTOPE_RATIO:
        case Kind.ISOTOPE:
        case Kind.CHARGE:
          currentPart.lines.push(Object.assign({}, line, {
            multiplier: 1
          }));
          break;

        case Kind.OPENING_PARENTHESIS:
          openingParenthesis(currentPart);
          break;

        case Kind.CLOSING_PARENTHESIS:
          closingParenthesis(currentPart);
          break;

        case Kind.PRE_MULTIPLIER:
          preMultiplier(currentPart, line);
          break;

        case Kind.MULTIPLIER:
          postMultiplier(currentPart, line.value, previousKind);
          break;

        case Kind.SALT:
          globalPartMultiplier(currentPart);
          currentPart = createNewPart();
          parts.push(currentPart);
          break;

        case Kind.ANCHOR:
          // we ignore anchors to create the parts and canonized MF
          break;

        case Kind.COMMENT:
          // we ignore comments to create the parts and canonized MF
          break;

        case Kind.TEXT:
          break;

        default:
          throw new Error(`Can not process mf having: ${line.kind}`);
      }

      previousKind = line.kind;
    }

    globalPartMultiplier(currentPart);
    if (shouldExpandGroups) expandGroups(parts);
    return combineAtomsIsotopesCharges(parts);
  };

  function createNewPart() {
    let currentMultiplier = {
      value: 1,
      fromIndex: 0
    };
    return {
      lines: [],
      multipliers: [currentMultiplier],
      currentMultiplier
    };
  }

  function openingParenthesis(currentPart) {
    currentPart.currentMultiplier = {
      value: 1,
      fromIndex: currentPart.lines.length
    };
    currentPart.multipliers.push(currentPart.currentMultiplier);
  }

  function closingParenthesis(currentPart) {
    currentPart.currentMultiplier = currentPart.multipliers.pop();

    if (currentPart.currentMultiplier !== 1) {
      for (let i = currentPart.currentMultiplier.fromIndex; i < currentPart.lines.length; i++) {
        currentPart.lines[i].multiplier *= currentPart.currentMultiplier.value;
      }
    }
  }

  function preMultiplier(currentPart, line) {
    currentPart.currentMultiplier.value *= line.value;
  }

  function globalPartMultiplier(currentPart) {
    for (let i = currentPart.multipliers[0].fromIndex; i < currentPart.lines.length; i++) {
      currentPart.lines[i].multiplier *= currentPart.multipliers[0].value;
    }
  }

  function postMultiplier(currentPart, value, previousKind) {
    if (previousKind === Kind.CLOSING_PARENTHESIS) {
      // need to apply to everything till the previous parenthesis
      for (let i = currentPart.currentMultiplier.fromIndex; i < currentPart.lines.length; i++) {
        currentPart.lines[i].multiplier *= value;
      }
    } else {
      // just applies to the previous element
      currentPart.lines[currentPart.lines.length - 1].multiplier *= value;
    }
  }

  function expandGroups(parts) {
    for (let part of parts) {
      let expanded = false;

      for (let i = 0; i < part.lines.length; i++) {
        let line = part.lines[i];

        if (line.kind === Kind.ATOM) {
          let group = groupsObject[line.value];

          if (group) {
            expanded = true;

            for (let element of group.elements) {
              if (element.isotope) {
                part.lines.push({
                  kind: 'isotope',
                  value: {
                    atom: element.symbol,
                    isotope: element.isotope
                  },
                  multiplier: line.multiplier * element.number
                });
              } else {
                part.lines.push({
                  kind: 'atom',
                  value: element.symbol,
                  multiplier: line.multiplier * element.number
                });
              }
            }

            part.lines[i] = undefined;
          }
        }
      }

      if (expanded) part.lines = part.lines.filter(a => a);
    }
  }

  function combineAtomsIsotopesCharges(parts) {
    let results = [];

    for (let part of parts) {
      let result = [];
      results.push(result);
      calculateAndSortKeys(part);
      let currentKey = '';

      for (let key of part.keys) {
        if (key.key === Kind.CHARGE) {
          if (currentKey !== key.key) {
            result.push({
              kind: Kind.CHARGE,
              value: key.value.value * key.value.multiplier
            });
          } else {
            result[result.length - 1].value += key.value.value * key.value.multiplier;
          }
        } else {
          if (currentKey !== key.key) {
            result.push(key.value);
          } else {
            result[result.length - 1].multiplier += key.value.multiplier;
          }
        }

        currentKey = key.key;
      }

      result.sort((a, b) => {
        if (a.kind === Kind.CHARGE) return 1;
        if (b.kind === Kind.CHARGE) return -1;
        let atomA = a.kind === Kind.ATOM ? a.value : a.value.atom;
        let atomB = b.kind === Kind.ATOM ? b.value : b.value.atom;
        if (atomA !== atomB) return src$i(atomA, atomB); // same atome but some isotopes ...

        if (a.kind === Kind.ATOM) return -1;
        if (b.kind === Kind.ATOM) return 1;
        if (a.kind === Kind.ISOTOPE) return -1;
        if (b.kind === Kind.ISOTOPE) return 1;
        if (a.kind === Kind.ISOTOPE_RATIO) return -1;
        if (b.kind === Kind.ISOTOPE_RATIO) return 1;
        return 0;
      });
    }

    return results;
  }

  function calculateAndSortKeys(part) {
    part.keys = [];

    for (let line of part.lines) {
      part.keys.push({
        key: getKey(line),
        value: line
      });
    }

    part.keys.sort((a, b) => stringComparator(a.key, b.key));
  }

  function getKey(line) {
    let key = [line.kind];

    switch (line.kind) {
      case Kind.CHARGE:
        break;

      default:
        if (typeof line.value === 'string') {
          key.push(line.value);
        } else {
          for (let prop of Object.keys(line.value).sort()) {
            key.push(line.value[prop]);
          }
        }

    }

    return key.join('-');
  }

  function stringComparator(a, b) {
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
  }

  class MF$3 {
    constructor(mf, options = {}) {
      if (options.ensureCase) {
        mf = ensureCase(mf);
      }

      this.parsed = parse(mf);
      this.cache = {};
    }

    toDisplay() {
      if (!this.cache.displayed) this.cache.displayed = toDisplay(this.parsed);
      return this.cache.displayed;
    }

    toHtml() {
      if (!this.cache.html) {
        this.toDisplay();
        this.cache.html = toHtml(this.cache.displayed);
      }

      return this.cache.html;
    }

    toParts(options) {
      if (!this.cache.parts) {
        this.cache.parts = toParts(this.parsed, options);
      }

      return this.cache.parts;
    }
    /**
     * Returns an object with the global MF, global charge, monoisotopic mass and mass
     * as well as the same informations for all the parts
     * @param {object} [options={}] options
     */


    getInfo(options = {}) {
      if (!this.cache.info) {
        this.toParts();
        this.cache.info = getInfo$1(this.cache.parts, options);
      }

      return this.cache.info;
    }
    /**
     * Returns an object with the elemental analysis
     */


    getEA(options = {}) {
      if (!this.cache.ea) {
        this.toParts();
        this.cache.ea = getEA(this.cache.parts);
      }

      return this.cache.ea;
    }
    /**
     * Returns an array with each atom and isotopic composition
     */


    getIsotopesInfo(options = {}) {
      if (!this.cache.isotopesInfo) {
        this.toParts();
        this.cache.isotopesInfo = getIsotopesInfo(this.cache.parts);
      }

      return this.cache.isotopesInfo;
    }
    /**
     * Get a canonized MF
     */


    toMF() {
      if (!this.cache.mf) {
        this.toParts();
        this.cache.mf = partsToMF(this.cache.parts);
      }

      return this.cache.mf;
    }
    /**
     * Get a canonized MF
     */


    toNeutralMF() {
      if (!this.cache.neutralMF) {
        this.toParts();
        this.cache.neutralMF = partsToMF(this.cache.parts, {
          neutral: true
        });
      }

      return this.cache.neutralMF;
    }

    canonize() {
      this.toParts();
      this.cache.displayed = partsToDisplay(this.cache.parts);
      this.cache.html = undefined;
    }

  }

  var MF_1 = MF$3;

  /**
   * Parse a molecular formula and converts it to an HTML code
   * @param {String} mf String containing the molecular formula
   */


  function parseToHtml(mf) {
    let parsed = parse(mf);
    let display = toDisplay(parsed);
    return toHtml(display);
  }

  var src$h = {
    Kind: Kind,
    Format: Format,
    Style: Style$1,
    parse: parse,
    ensureCase: ensureCase,
    toDisplay,
    toHtml,
    parseToHtml,
    MF: MF_1
  };

  /**
   * @param {object}   [entry={}}]
   * @param {object}   [options={}}]
   * @param {number}   [options.min=-Infinity] - Minimal unsaturation
   * @param {number}   [options.max=+Infinity] - Maximal unsaturation
   * @param {number}   [options.onlyInteger=false] - Integer unsaturation
   * @param {number}   [options.onlyNonInteger=false] - Non integer unsaturation
   * @return {boolean}
   */

  var unsaturationMatcher = function unsaturationMatcher(entry, options = {}) {
    const {
      min = Number.MIN_SAFE_INTEGER,
      max = Number.MAX_SAFE_INTEGER,
      onlyInteger,
      onlyNonInteger
    } = options;

    if (entry.unsaturation !== undefined) {
      if (entry.unsaturation < min || entry.unsaturation > max) return false;
      if (onlyInteger && !Number.isInteger(entry.unsaturation)) return false;
      if (onlyNonInteger && Number.isInteger(entry.unsaturation)) return false;
    }

    return true;
  };

  /**
   * Returns true if the entry containing MF information match
   * @param {object}   [entry={}}] - object containing mw, ...
   * @param {object}   [options={}}]
   * @param {number}   [options.minMW=0] - Minimal molecular weight
   * @param {number}   [options.maxMW=+Infinity] - Maximal molecular weight
   * @param {number}   [options.minEM=0] - Minimal monoisotopic mass
   * @param {number}   [options.maxEM=+Infinity] - Maximal monoisotopic mass
   * @param {number}   [options.minCharge=-Infinity] - Minimal charge
   * @param {number}   [options.maxCharge=+Infinity] - Maximal charge
   * @param {object}   [options.unsaturation={}}]
   * @param {number}   [options.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number}   [options.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number}   [options.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number}   [options.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {object}   [options.atoms] - object of atom:{min, max}
   * @return {boolean}
   */


  var generalMatcher = function generalMatcher(entry, options = {}) {
    const {
      minMW = 0,
      maxMW = +Infinity,
      minEM = 0,
      maxEM = +Infinity,
      minCharge = Number.MIN_SAFE_INTEGER,
      maxCharge = Number.MAX_SAFE_INTEGER,
      unsaturation = {},
      atoms
    } = options;

    if (entry.mw !== undefined) {
      if (entry.mw < minMW || entry.mw > maxMW) return false;
    }

    if (entry.em !== undefined) {
      if (entry.em < minEM || entry.em > maxEM) return false;
    }

    if (entry.charge !== undefined) {
      if (entry.charge < minCharge || entry.charge > maxCharge) return false;
    }

    if (unsaturation !== undefined && entry.unsaturation !== undefined) {
      if (!unsaturationMatcher(entry, unsaturation)) return false;
    }

    if (entry.atoms !== undefined && atoms) {
      // all the atoms of the entry must fit in the range
      for (let atom of Object.keys(entry.atoms)) {
        if (!atoms[atom]) return false;
        if (entry.atoms[atom] < atoms[atom].min) return false;
        if (entry.atoms[atom] > atoms[atom].max) return false;
      }
    }

    return true;
  };

  const {
    ELECTRON_MASS: ELECTRON_MASS$4
  } = constants;

  var getMsem = function getMsem(em, charge) {
    if (charge > 0) {
      return em / charge - ELECTRON_MASS$4;
    } else if (charge < 0) {
      return em / (charge * -1) + ELECTRON_MASS$4;
    } else {
      return 0;
    }
  };

  /**
   * Returns an object containing:
   * {ms: {em, charge, ionization}, ionization: {}}
   * We return the ionization in order to know which one has been selected
   */


  var getMsInfo = function getMsInfo(entry, options = {}) {
    const {
      allowNeutralMolecules,
      ionization = {
        mf: '',
        em: 0,
        charge: 0
      },
      forceIonization = false,
      targetMass
    } = options;
    let realIonization = ionization;

    if (!forceIonization && entry.ionization && entry.ionization.mf !== '') {
      realIonization = entry.ionization;
    }

    let ms = {
      ionization: realIonization.mf,
      em: 0,
      charge: entry.charge + realIonization.charge
    };

    if (ms.charge !== 0) {
      ms.em = getMsem(entry.em + realIonization.em, ms.charge);
    } else if (allowNeutralMolecules) {
      ms.em = entry.em + realIonization.em;
    }

    if (targetMass) {
      ms.delta = targetMass - ms.em;
      ms.ppm = (targetMass - ms.em) / ms.em * 1e6;
    }

    return {
      ms,
      ionization: realIonization
    };
  };

  /**
   * This function returns an array with absolute values
   * @param {Array<Number>} array
   * @return {Number}
   */
  function xAbsolute(array) {
    let tmpArray = array.slice();

    for (let i = 0; i < tmpArray.length; i++) {
      tmpArray[i] = Math.abs(tmpArray[i]);
    }

    return tmpArray;
  }

  const toString$8 = Object.prototype.toString;
  function isAnyArray$6(object) {
    return toString$8.call(object).endsWith('Array]');
  }

  var medianQuickselect_min$1 = createCommonjsModule$1(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); !0;) {
          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; !0;) {
            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;
    })();
  });

  function median$2(input) {
    if (!isAnyArray$6(input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }

    return medianQuickselect_min$1(input.slice());
  }

  /**
   * This function calculates the median after taking the reimAbsolute values of the points
   * @param {Array<Number>} array - the array that will be rotated
   * @return {Number}
   */

  function xAbsoluteMedian(array) {
    return median$2(xAbsolute(array));
  }

  /**

  /**
   * This function xAdd the first array by the second array or a constant value to each element of the first array
   * @param {Array<Number>} array1 - the array that will be rotated
   * @param {Array|Number} array2
   * @return {Array}
   */
  function xAdd(array1, array2) {
    let isConstant = false;
    let constant;

    if (Array.isArray(array2)) {
      if (array1.length !== array2.length) {
        throw new Error('sub: size of array1 and array2 must be identical');
      }
    } else {
      isConstant = true;
      constant = Number(array2);
    }

    let array3 = new Array(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;
  }

  /**

  /**
   * This function xMultiply the first array by the second array or a constant value to each element of the first array
   * @param {Array} array1 - the array that will be rotated
   * @param {Array|Number} array2
   * @return {Float64Array}
   */
  function xMultiply(array1, array2) {
    let isConstant = false;
    let constant;

    if (Array.isArray(array2)) {
      if (array1.length !== array2.length) {
        throw new Error('sub: size of array1 and array2 must be identical');
      }
    } else {
      isConstant = true;
      constant = Number(array2);
    }

    let 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;
  }

  function xDotProduct(A, B) {
    let g = xMultiply(A, B);
    let result = 0;

    for (let i = 0; i < A.length; i++) {
      result += g[i];
    }

    return result;
  }

  /**
   * Calculates the cross-correlation between 2 vectors
   * @param {Array<Number>} [A] - fixed array
   * @param {Array<Number>} [B] - sweeping array
   * @param {object} [options={}]
   * @param {number} [options.tau = 1] - sweep increment size (in number of points, min = 1, max = A.length)
   * @param {number} [options.lag = A.length - 1] - scalar lag parameter
   */

  function xCrossCorrelation(A, B, options = {}) {
    let {
      tau = 1,
      lag = A.length - 1
    } = options;
    let result = new Float64Array(1 + 2 * lag / tau);

    if (A.length === B.length) {
      let n = B.length;
      let g = new Float64Array(2 * n);
      let q = new Float64Array(2 * n);

      for (let i = 0; i < n; i++) {
        q[n + i] = B[i];
      }

      for (let i = n * 2 - (tau - 1); i > 0; i -= tau) {
        let k = 0;

        for (let j = i; j < n * 2; j++) {
          g[k] = q[j];
          k++;
        }

        let w = [];

        for (let l = 0; l < n; l++) {
          w[l] = g[l];
        }

        result[(k - (n - lag)) / tau] = xDotProduct(A, w);
      }
    }

    return result;
  }

  /**
   * Calculates the auto-correlation of a vector
   * @param {Array<Number>} [A] - the array that will be fixed
   * @param {object} [options={}]
   * @param {number} [options.tau = 1] - sweep increment size (in number of points, min = 1, max = A.length)
   * @param {number} [options.lag = A.length - 1] - scalar lag parameter
   */

  function xAutoCorrelation(A, options = {}) {
    return xCrossCorrelation(A, A, options);
  }

  /**
   * This function xSubtract the first array by the second array or a constant value from each element of the first array
   * @param {Array<Number>} array1 - the array that will be rotated
   * @return {object}
   */
  function xBoxPlot(array) {
    array = array.slice(0).sort((a, b) => a - b);

    if (array.length < 5) {
      throw Error('xBoxPlot: can not calculate info if array contains less than 3 elements');
    }

    let info = {
      Q1: 0.0,
      Q2: 0.0,
      Q3: 0.0,
      min: array[0],
      max: array[array.length - 1]
    };
    let q1max, q3min;

    if (array.length % 2 === 1) {
      // odd
      let middle = (array.length - 1) / 2;
      info.Q2 = array[middle];
      q1max = middle - 1;
      q3min = middle + 1;
    } else {
      // even
      q3min = array.length / 2;
      q1max = q3min - 1;
      info.Q2 = (array[q1max] + array[q3min]) / 2;
    }

    if (q1max % 2 === 0) {
      info.Q1 = array[q1max / 2];
      info.Q3 = array[(array.length + q3min - 1) / 2];
    } else {
      info.Q1 = (array[(q1max + 1) / 2] + array[(q1max - 1) / 2]) / 2;
      let middleOver = (array.length + q3min) / 2;
      info.Q3 = (array[middleOver] + array[middleOver - 1]) / 2;
    }

    return info;
  }

  /**

  /**
   * Calculates the correlation between 2 vectors
   * https://en.wikipedia.org/wiki/Correlation_and_dependence
   *
   * @param {Array<Number>} [A] - the array that will be rotated
   * @param {Array<Number>} [B]
   * @return {Array}
   */
  function xCorrelation(A, B) {
    let n = A.length;
    let sumA = 0;
    let sumA2 = 0;
    let sumB = 0;
    let sumB2 = 0;
    let sumAB = 0;

    for (let i = 0; i < n; i++) {
      let a = A[i];
      let b = B[i];
      sumA += a;
      sumA2 += a ** 2;
      sumB += b;
      sumB2 += b ** 2;
      sumAB += a * b;
    }

    return (n * sumAB - sumA * sumB) / (Math.sqrt(n * sumA2 - sumA ** 2) * Math.sqrt(n * sumB2 - sumB ** 2));
  }

  /**

  /**
   * This function divide the first array by the second array or a constant value to each element of the first array
   * @param {Array<Number>} array1 - the array that will be rotated
   * @param {Array<Number>|Number} array2
   * @return {Array}
   */
  function xDivide(array1, array2) {
    let isConstant = false;
    let constant;

    if (Array.isArray(array2)) {
      if (array1.length !== array2.length) {
        throw new Error('sub: size of array1 and array2 must be identical');
      }
    } else {
      isConstant = true;
      constant = Number(array2);
    }

    let array3 = new Array(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 the closest index of a `target` in an ordered array
   * @param {array<Number>} array
   * @param {number} target
   */
  function xFindClosestIndex$1(array, target) {
    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;
    }
  }

  /**
   * Returns an object with {fromIndex, toIndex} for a specific from / to
   * @param {array} x
   * @param {object} [options={}]
   * @param {number} [options.from] - First value for xyIntegration in the X scale
   * @param {number} [options.fromIndex=0] - First point for xyIntegration
   * @param {number} [options.to] - Last value for xyIntegration in the X scale
   * @param {number} [options.toIndex=x.length-1] - Last point for xyIntegration
   */

  function xGetFromToIndex(x, options = {}) {
    let {
      fromIndex,
      toIndex,
      from,
      to
    } = options;

    if (fromIndex === undefined) {
      if (from !== undefined) {
        fromIndex = xFindClosestIndex$1(x, from);
      } else {
        fromIndex = 0;
      }
    }

    if (toIndex === undefined) {
      if (to !== undefined) {
        toIndex = xFindClosestIndex$1(x, to);
      } else {
        toIndex = x.length - 1;
      }
    }

    if (fromIndex > toIndex) [fromIndex, toIndex] = [toIndex, fromIndex];
    return {
      fromIndex,
      toIndex
    };
  }

  /**
   *  Returns the targetIndex
   * @param {array} [x]
   * @param {object} [options={}]
   * @param {number} [options.target]
   * @param {number} [options.targetIndex=0]
   * @param {number}
   */

  function xGetTargetIndex(x, options = {}) {
    let {
      target,
      targetIndex
    } = options;

    if (targetIndex === undefined) {
      if (target !== undefined) {
        return xFindClosestIndex$1(x, target);
      } else {
        return 0;
      }
    }

    return targetIndex;
  }

  /**
   * Returns true if x is monotone
   * @param {Array} array
   * @return {boolean}
   */
  function xIsMonotone(array) {
    if (array.length < 3) return true;

    if (array[0] < array[1]) {
      for (let i = 0; i < array.length - 1; i++) {
        if (array[i] >= array[i + 1]) return false;
      }
    } else {
      for (let i = 0; i < array.length - 1; i++) {
        if (array[i] <= array[i + 1]) return false;
      }
    }

    return true;
  }

  var d3Array = createCommonjsModule$1(function (module, exports) {
    (function (global, factory) {
      factory(exports) ;
    })(commonjsGlobal$1, function (exports) {

      function ascending(a, b) {
        return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
      }

      function bisector(compare) {
        if (compare.length === 1) compare = ascendingComparator(compare);
        return {
          left: function (a, x, lo, hi) {
            if (lo == null) lo = 0;
            if (hi == null) hi = a.length;

            while (lo < hi) {
              var mid = lo + hi >>> 1;
              if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid;
            }

            return lo;
          },
          right: function (a, x, lo, hi) {
            if (lo == null) lo = 0;
            if (hi == null) hi = a.length;

            while (lo < hi) {
              var mid = lo + hi >>> 1;
              if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1;
            }

            return lo;
          }
        };
      }

      function ascendingComparator(f) {
        return function (d, x) {
          return ascending(f(d), x);
        };
      }

      var ascendingBisect = bisector(ascending);
      var bisectRight = ascendingBisect.right;
      var bisectLeft = ascendingBisect.left;

      function descending(a, b) {
        return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
      }

      function number$1(x) {
        return x === null ? NaN : +x;
      }

      function variance(array, f) {
        var n = array.length,
            m = 0,
            a,
            d,
            s = 0,
            i = -1,
            j = 0;

        if (f == null) {
          while (++i < n) {
            if (!isNaN(a = number$1(array[i]))) {
              d = a - m;
              m += d / ++j;
              s += d * (a - m);
            }
          }
        } else {
          while (++i < n) {
            if (!isNaN(a = number$1(f(array[i], i, array)))) {
              d = a - m;
              m += d / ++j;
              s += d * (a - m);
            }
          }
        }

        if (j > 1) return s / (j - 1);
      }

      function deviation(array, f) {
        var v = variance(array, f);
        return v ? Math.sqrt(v) : v;
      }

      function extent(array, f) {
        var i = -1,
            n = array.length,
            a,
            b,
            c;

        if (f == null) {
          while (++i < n) if ((b = array[i]) != null && b >= b) {
            a = c = b;
            break;
          }

          while (++i < n) if ((b = array[i]) != null) {
            if (a > b) a = b;
            if (c < b) c = b;
          }
        } else {
          while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) {
            a = c = b;
            break;
          }

          while (++i < n) if ((b = f(array[i], i, array)) != null) {
            if (a > b) a = b;
            if (c < b) c = b;
          }
        }

        return [a, c];
      }

      function constant(x) {
        return function () {
          return x;
        };
      }

      function identity(x) {
        return x;
      }

      function range(start, stop, step) {
        start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
        var i = -1,
            n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
            range = new Array(n);

        while (++i < n) {
          range[i] = start + i * step;
        }

        return range;
      }

      var e10 = Math.sqrt(50);
      var e5 = Math.sqrt(10);
      var e2 = Math.sqrt(2);

      function ticks(start, stop, count) {
        var step = tickStep(start, stop, count);
        return range(Math.ceil(start / step) * step, Math.floor(stop / step) * step + step / 2, // inclusive
        step);
      }

      function tickStep(start, stop, count) {
        var step0 = Math.abs(stop - start) / Math.max(0, count),
            step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
            error = step0 / step1;
        if (error >= e10) step1 *= 10;else if (error >= e5) step1 *= 5;else if (error >= e2) step1 *= 2;
        return stop < start ? -step1 : step1;
      }

      function sturges(values) {
        return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
      }

      function number(x) {
        return +x;
      }

      function histogram() {
        var value = identity,
            domain = extent,
            threshold = sturges;

        function histogram(data) {
          var i,
              n = data.length,
              x,
              values = new Array(n); // Coerce values to numbers.

          for (i = 0; i < n; ++i) {
            values[i] = +value(data[i], i, data);
          }

          var xz = domain(values),
              x0 = +xz[0],
              x1 = +xz[1],
              tz = threshold(values, x0, x1); // Convert number of thresholds into uniform thresholds.

          if (!Array.isArray(tz)) tz = ticks(x0, x1, +tz); // Coerce thresholds to numbers, ignoring any outside the domain.

          var m = tz.length;

          for (i = 0; i < m; ++i) tz[i] = +tz[i];

          while (tz[0] <= x0) tz.shift(), --m;

          while (tz[m - 1] >= x1) tz.pop(), --m;

          var bins = new Array(m + 1),
              bin; // Initialize bins.

          for (i = 0; i <= m; ++i) {
            bin = bins[i] = [];
            bin.x0 = i > 0 ? tz[i - 1] : x0;
            bin.x1 = i < m ? tz[i] : x1;
          } // Assign data to bins by value, ignoring any outside the domain.


          for (i = 0; i < n; ++i) {
            x = values[i];

            if (x0 <= x && x <= x1) {
              bins[bisectRight(tz, x, 0, m)].push(data[i]);
            }
          }

          return bins;
        }

        histogram.value = function (_) {
          return arguments.length ? (value = typeof _ === "function" ? _ : constant(+_), histogram) : value;
        };

        histogram.domain = function (_) {
          return arguments.length ? (domain = typeof _ === "function" ? _ : constant([+_[0], +_[1]]), histogram) : domain;
        };

        histogram.thresholds = function (_) {
          if (!arguments.length) return threshold;
          threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(Array.prototype.map.call(_, number)) : constant(+_);
          return histogram;
        };

        return histogram;
      }

      function quantile(array, p, f) {
        if (f == null) f = number$1;
        if (!(n = array.length)) return;
        if ((p = +p) <= 0 || n < 2) return +f(array[0], 0, array);
        if (p >= 1) return +f(array[n - 1], n - 1, array);
        var n,
            h = (n - 1) * p,
            i = Math.floor(h),
            a = +f(array[i], i, array),
            b = +f(array[i + 1], i + 1, array);
        return a + (b - a) * (h - i);
      }

      function freedmanDiaconis(values, min, max) {
        values.sort(ascending);
        return Math.ceil((max - min) / (2 * (quantile(values, 0.75) - quantile(values, 0.25)) * Math.pow(values.length, -1 / 3)));
      }

      function scott(values, min, max) {
        return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
      }

      function max(array, f) {
        var i = -1,
            n = array.length,
            a,
            b;

        if (f == null) {
          while (++i < n) if ((b = array[i]) != null && b >= b) {
            a = b;
            break;
          }

          while (++i < n) if ((b = array[i]) != null && b > a) a = b;
        } else {
          while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) {
            a = b;
            break;
          }

          while (++i < n) if ((b = f(array[i], i, array)) != null && b > a) a = b;
        }

        return a;
      }

      function mean(array, f) {
        var s = 0,
            n = array.length,
            a,
            i = -1,
            j = n;

        if (f == null) {
          while (++i < n) if (!isNaN(a = number$1(array[i]))) s += a;else --j;
        } else {
          while (++i < n) if (!isNaN(a = number$1(f(array[i], i, array)))) s += a;else --j;
        }

        if (j) return s / j;
      }

      function median(array, f) {
        var numbers = [],
            n = array.length,
            a,
            i = -1;

        if (f == null) {
          while (++i < n) if (!isNaN(a = number$1(array[i]))) numbers.push(a);
        } else {
          while (++i < n) if (!isNaN(a = number$1(f(array[i], i, array)))) numbers.push(a);
        }

        return quantile(numbers.sort(ascending), 0.5);
      }

      function merge(arrays) {
        var n = arrays.length,
            m,
            i = -1,
            j = 0,
            merged,
            array;

        while (++i < n) j += arrays[i].length;

        merged = new Array(j);

        while (--n >= 0) {
          array = arrays[n];
          m = array.length;

          while (--m >= 0) {
            merged[--j] = array[m];
          }
        }

        return merged;
      }

      function min(array, f) {
        var i = -1,
            n = array.length,
            a,
            b;

        if (f == null) {
          while (++i < n) if ((b = array[i]) != null && b >= b) {
            a = b;
            break;
          }

          while (++i < n) if ((b = array[i]) != null && a > b) a = b;
        } else {
          while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) {
            a = b;
            break;
          }

          while (++i < n) if ((b = f(array[i], i, array)) != null && a > b) a = b;
        }

        return a;
      }

      function pairs(array) {
        var i = 0,
            n = array.length - 1,
            p = array[0],
            pairs = new Array(n < 0 ? 0 : n);

        while (i < n) pairs[i] = [p, p = array[++i]];

        return pairs;
      }

      function permute(array, indexes) {
        var i = indexes.length,
            permutes = new Array(i);

        while (i--) permutes[i] = array[indexes[i]];

        return permutes;
      }

      function scan(array, compare) {
        if (!(n = array.length)) return;
        var i = 0,
            n,
            j = 0,
            xi,
            xj = array[j];
        if (!compare) compare = ascending;

        while (++i < n) if (compare(xi = array[i], xj) < 0 || compare(xj, xj) !== 0) xj = xi, j = i;

        if (compare(xj, xj) === 0) return j;
      }

      function shuffle(array, i0, i1) {
        var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
            t,
            i;

        while (m) {
          i = Math.random() * m-- | 0;
          t = array[m + i0];
          array[m + i0] = array[i + i0];
          array[i + i0] = t;
        }

        return array;
      }

      function sum(array, f) {
        var s = 0,
            n = array.length,
            a,
            i = -1;

        if (f == null) {
          while (++i < n) if (a = +array[i]) s += a; // Note: zero and null are equivalent.

        } else {
          while (++i < n) if (a = +f(array[i], i, array)) s += a;
        }

        return s;
      }

      function transpose(matrix) {
        if (!(n = matrix.length)) return [];

        for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
          for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
            row[j] = matrix[j][i];
          }
        }

        return transpose;
      }

      function length(d) {
        return d.length;
      }

      function zip() {
        return transpose(arguments);
      }

      var version = "0.7.1";
      exports.version = version;
      exports.bisect = bisectRight;
      exports.bisectRight = bisectRight;
      exports.bisectLeft = bisectLeft;
      exports.ascending = ascending;
      exports.bisector = bisector;
      exports.descending = descending;
      exports.deviation = deviation;
      exports.extent = extent;
      exports.histogram = histogram;
      exports.thresholdFreedmanDiaconis = freedmanDiaconis;
      exports.thresholdScott = scott;
      exports.thresholdSturges = sturges;
      exports.max = max;
      exports.mean = mean;
      exports.median = median;
      exports.merge = merge;
      exports.min = min;
      exports.pairs = pairs;
      exports.permute = permute;
      exports.quantile = quantile;
      exports.range = range;
      exports.scan = scan;
      exports.shuffle = shuffle;
      exports.sum = sum;
      exports.ticks = ticks;
      exports.tickStep = tickStep;
      exports.transpose = transpose;
      exports.variance = variance;
      exports.zip = zip;
    });
  });

  const {
    bisectRight
  } = d3Array;

  const quincunx = (u, v, w, q) => {
    const n = u.length - 1;
    u[0] = 0;
    v[0] = 0;
    w[0] = 0;
    v[1] = v[1] / u[1];
    w[1] = w[1] / u[1];

    for (let i = 2; i < n; ++i) {
      u[i] = u[i] - u[i - 2] * w[i - 2] * w[i - 2] - u[i - 1] * v[i - 1] * v[i - 1];
      v[i] = (v[i] - u[i - 1] * v[i - 1] * w[i - 1]) / u[i];
      w[i] = w[i] / u[i];
    }

    for (let i = 2; i < n; ++i) {
      q[i] = q[i] - v[i - 1] * q[i - 1] - w[i - 2] * q[i - 2];
    }

    for (let i = 1; i < n; ++i) {
      q[i] = q[i] / u[i];
    }

    q[n - 2] = q[n - 2] - v[n - 2] * q[n - 1];

    for (let i = n - 3; i > 0; --i) {
      q[i] = q[i] - v[i] * q[i + 1] - w[i] * q[i + 2];
    }
  };

  const smoothingSpline = (x, y, sigma, lambda) => {
    const n = x.length - 1;
    const h = new Array(n + 1);
    const r = new Array(n + 1);
    const f = new Array(n + 1);
    const p = new Array(n + 1);
    const q = new Array(n + 1);
    const u = new Array(n + 1);
    const v = new Array(n + 1);
    const w = new Array(n + 1);
    const params = x.map(() => [0, 0, 0, 0]);
    params.pop();
    const mu = 2 * (1 - lambda) / (3 * lambda);

    for (let i = 0; i < n; ++i) {
      h[i] = x[i + 1] - x[i];
      r[i] = 3 / h[i];
    }

    q[0] = 0;

    for (let i = 1; i < n; ++i) {
      f[i] = -(r[i - 1] + r[i]);
      p[i] = 2 * (x[i + 1] - x[i - 1]);
      q[i] = 3 * (y[i + 1] - y[i]) / h[i] - 3 * (y[i] - y[i - 1]) / h[i - 1];
    }

    q[n] = 0;

    for (let i = 1; i < n; ++i) {
      u[i] = r[i - 1] * r[i - 1] * sigma[i - 1] + f[i] * f[i] * sigma[i] + r[i] * r[i] * sigma[i + 1];
      u[i] = mu * u[i] + p[i];
    }

    for (let i = 1; i < n - 1; ++i) {
      v[i] = f[i] * r[i] * sigma[i] + r[i] * f[i + 1] * sigma[i + 1];
      v[i] = mu * v[i] + h[i];
    }

    for (let i = 1; i < n - 2; ++i) {
      w[i] = mu * r[i] * r[i + 1] * sigma[i + 1];
    }

    quincunx(u, v, w, q);
    params[0][3] = y[0] - mu * r[0] * q[1] * sigma[0];
    params[1][3] = y[1] - mu * (f[1] * q[1] + r[1] * q[2]) * sigma[0];
    params[0][0] = q[1] / (3 * h[0]);
    params[0][1] = 0;
    params[0][2] = (params[1][3] - params[0][3]) / h[0] - q[1] * h[0] / 3;
    r[0] = 0;

    for (let i = 1; i < n; ++i) {
      params[i][0] = (q[i + 1] - q[i]) / (3 * h[i]);
      params[i][1] = q[i];
      params[i][2] = (q[i] + q[i - 1]) * h[i - 1] + params[i - 1][2];
      params[i][3] = r[i - 1] * q[i - 1] + f[i] * q[i] + r[i] * q[i + 1];
      params[i][3] = y[i] - mu * params[i][3] * sigma[i];
    }

    return params;
  };

  class SplineInterpolator {
    constructor(xIn, yIn, lambda = 1) {
      const indices = xIn.map((_, i) => i);
      indices.sort((i, j) => xIn[i] - xIn[j]);
      const x = indices.map(i => xIn[i]);
      const y = indices.map(i => yIn[i]);
      const n = indices.length;
      const sigma = indices.map(() => 1);
      this.n = n;
      this.x = x;
      this.y = y;
      this.params = smoothingSpline(x, y, sigma, lambda);
    }

    interpolate(v) {
      if (v === this.x[this.n - 1]) {
        return this.y[this.n - 1];
      }

      const i = Math.min(Math.max(0, bisectRight(this.x, v) - 1), this.n - 2);
      const [a, b, c, d] = this.params[i];
      v = v - this.x[i];
      return a * v * v * v + b * v * v + c * v + d;
    }

    max(step = 100) {
      const xStart = this.x[0];
      const xStop = this.x[this.n - 1];
      const delta = (xStop - xStart) / step;
      let maxValue = -Infinity;

      for (let i = 0, x = xStart; i < step; ++i, x += delta) {
        const y = this.interpolate(x);

        if (y > maxValue) {
          maxValue = y;
        }
      }

      return maxValue;
    }

    min(step = 100) {
      const xStart = this.x[0];
      const xStop = this.x[this.n - 1];
      const delta = (xStop - xStart) / step;
      let minValue = Infinity;

      for (let i = 0, x = xStart; i < step; ++i, x += delta) {
        const y = this.interpolate(x);

        if (y < minValue) {
          minValue = y;
        }
      }

      return minValue;
    }

    domain() {
      return [this.x[0], this.x[this.x.length - 1]];
    }

    range() {
      return [this.min(), this.max()];
    }

    curve(nInterval, domain = null) {
      domain = domain || this.domain();
      const delta = (domain[1] - domain[0]) / (nInterval - 1);
      const vals = new Array(nInterval);

      for (let i = 0; i < nInterval; ++i) {
        const x = delta * i + domain[0];
        vals[i] = [x, this.interpolate(x)];
      }

      return vals;
    }

  }

  var splineInterpolator = SplineInterpolator;

  /* eslint-disable no-loss-of-precision */

  /*
  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.
  */
  // Coefficients for erfcinv on [0, 0.5]:
  const Y1 = 8.91314744949340820313e-2;
  const P1 = [-5.38772965071242932965e-3, 8.22687874676915743155e-3, 2.19878681111168899165e-2, -3.65637971411762664006e-2, -1.26926147662974029034e-2, 3.34806625409744615033e-2, -8.36874819741736770379e-3, -5.08781949658280665617e-4];
  const Q1 = [8.86216390456424707504e-4, -2.33393759374190016776e-3, 7.95283687341571680018e-2, -5.27396382340099713954e-2, -7.1228902341542847553e-1, 6.62328840472002992063e-1, 1.56221558398423026363, -1.56574558234175846809, -9.70005043303290640362e-1, 1]; // Coefficients for erfcinv for 0.5 > 1-x >= 0:

  const Y2 = 2.249481201171875;
  const P2 = [-3.67192254707729348546, 2.11294655448340526258e1, 1.7445385985570866523e1, -4.46382324441786960818e1, -1.88510648058714251895e1, 1.76447298408374015486e1, 8.37050328343119927838, 1.05264680699391713268e-1, -2.02433508355938759655e-1];
  const Q2 = [1.72114765761200282724, -2.26436933413139721736e1, 1.08268667355460159008e1, 4.85609213108739935468e1, -2.01432634680485188801e1, -2.86608180499800029974e1, 3.9713437953343869095, 6.24264124854247537712, 1]; // Coefficients for erfcinv for sqrt( -log(1-x)):

  const Y3 = 8.07220458984375e-1;
  const P3 = [-6.81149956853776992068e-10, 2.85225331782217055858e-8, -6.79465575181126350155e-7, 2.14558995388805277169e-3, 2.90157910005329060432e-2, 1.42869534408157156766e-1, 3.37785538912035898924e-1, 3.87079738972604337464e-1, 1.17030156341995252019e-1, -1.63794047193317060787e-1, -1.31102781679951906451e-1];
  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, -2.30404776911882601748e-10, 4.60469890584317994083e-6, 1.57544617424960554631e-4, 1.87123492819559223345e-3, 9.50804701325919603619e-3, 1.85573306514231072324e-2, -2.22426529213447927281e-3, -3.50353787183177984712e-2];
  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, -2.81128735628831791805e-14, 4.62596163522878599135e-9, 4.49696789927706453732e-7, 1.49624783758342370182e-5, 2.09386317487588078668e-4, 1.05628862152492910091e-3, -1.12951438745580278863e-3, -1.67431005076633737133e-2];
  const Q5 = [2.82243172016108031869e-7, 2.75335474764726041141e-5, 9.64011807005165528527e-4, 1.60746087093676504695e-2, 1.38151865749083321638e-1, 5.91429344886417493481e-1, 1];

  function polyval(c, x) {
    let p = 0;

    for (const coef of c) {
      p = p * x + coef;
    }

    return p;
  }
  /**
   * Calculates a rational approximation.
   *
   * @private
   * @param {Number} x
   * @param {Number} v
   * @param {Array} P - array of polynomial coefficients
   * @param {Array} Q - array of polynomial coefficients
   * @param {Number} Y
   * @returns {Number} 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 {Number} x - input value
   * @returns {Number} 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 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.
  }

  function rayleighCdf(x, sigma = 1) {
    if (x < 0) {
      return 0;
    }

    return -Math.expm1(-Math.pow(x, 2) / (2 * Math.pow(sigma, 2)));
  }

  /**
   * Determine noise level by san plot metodology (https://doi.org/10.1002/mrc.4882)
   * @param {Array} data - real or magnitude spectra data.
   * @param {*} options
   */

  function xNoiseSanPlot(data, options = {}) {
    const {
      mask,
      cutOff,
      refine = true,
      magnitudeMode = false,
      scaleFactor = 1,
      factorStd = 5,
      fixOffset = true
    } = options;
    let input;

    if (Array.isArray(mask) && mask.length === data.length) {
      input = data.filter((_e, i) => !mask[i]);
    } else {
      input = data.slice();
    }

    if (scaleFactor > 1) {
      for (let i = 0; i < input.length; i++) {
        input[i] *= scaleFactor;
      }
    }

    input.sort((a, b) => b - a);

    if (fixOffset && !magnitudeMode) {
      let medianIndex = Math.floor(input.length / 2);
      let median = 0.5 * (input[medianIndex] + input[medianIndex + 1]);

      for (let i = 0; i < input.length; i++) {
        input[i] -= median;
      }
    }

    let firstNegativeValueIndex = input.findIndex(e => e < 0);
    let lastPositiveValueIndex = firstNegativeValueIndex - 1;

    for (let i = lastPositiveValueIndex; i >= 0; i--) {
      if (input[i] > 0) {
        lastPositiveValueIndex = i;
        break;
      }
    }

    let signPositive = new Float64Array(input.slice(0, lastPositiveValueIndex + 1));
    let signNegative = new Float64Array(input.slice(firstNegativeValueIndex));
    let cutOffDist = cutOff || determineCutOff(signPositive, {
      magnitudeMode
    });
    let pIndex = Math.floor(signPositive.length * cutOffDist);
    let initialNoiseLevelPositive = signPositive[pIndex];
    let skyPoint = signPositive[0];
    let initialNoiseLevelNegative;

    if (signNegative.length > 0) {
      let 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))];
      }
    }

    let correctionFactor = -simpleNormInv(cutOffDist / 2, {
      magnitudeMode
    });
    initialNoiseLevelPositive = initialNoiseLevelPositive / correctionFactor;
    initialNoiseLevelNegative = initialNoiseLevelNegative / correctionFactor;
    let effectiveCutOffDist, refinedCorrectionFactor;

    if (refine && cutOffSignalsIndexPlus > -1) {
      effectiveCutOffDist = (cutOffDist * cloneSignPositive.length + cutOffSignalsIndexPlus) / (cloneSignPositive.length + cutOffSignalsIndexPlus);
      refinedCorrectionFactor = -1 * simpleNormInv(effectiveCutOffDist / 2, {
        magnitudeMode
      });
      noiseLevelPositive /= refinedCorrectionFactor;

      if (cutOffSignalsIndexNeg > -1) {
        effectiveCutOffDist = (cutOffDist * cloneSignNegative.length + cutOffSignalsIndexNeg) / (cloneSignNegative.length + cutOffSignalsIndexNeg);
        refinedCorrectionFactor = -1 * simpleNormInv(effectiveCutOffDist / 2, {
          magnitudeMode
        });

        if (noiseLevelNegative !== 0) {
          noiseLevelNegative /= refinedCorrectionFactor;
        }
      }
    } else {
      noiseLevelPositive /= correctionFactor;
      noiseLevelNegative /= correctionFactor;
    }

    return {
      positive: noiseLevelPositive,
      negative: noiseLevelNegative,
      snr: skyPoint / noiseLevelPositive
    };
  }

  function determineCutOff(signPositive, options = {}) {
    let {
      magnitudeMode = false,
      considerList = {
        from: 0.5,
        step: 0.1,
        to: 0.9
      }
    } = options; //generate a list of values for

    let cutOff = [];
    let indexMax = signPositive.length - 1;

    for (let i = 0.01; i <= 0.99; i += 0.01) {
      let index = Math.round(indexMax * i);
      let value = -signPositive[index] / simpleNormInv([i / 2], {
        magnitudeMode
      });
      cutOff.push([i, value]);
    }

    let minKi = Number.MAX_SAFE_INTEGER;
    let {
      from,
      to,
      step
    } = considerList;
    let delta = step / 2;
    let whereToCutStat = 0.5;

    for (let i = from; i <= to; i += step) {
      let floor = i - delta;
      let top = i + delta;
      let elementsOfCutOff = cutOff.filter(e => e[0] < top && e[0] > floor);
      let averageValue = elementsOfCutOff.reduce((a, b) => a + Math.abs(b[1]), 0);
      let kiSqrt = 0;

      for (let j = 0; j < elementsOfCutOff.length; j++) {
        kiSqrt += Math.pow(elementsOfCutOff[j][1] - averageValue, 2);
      }

      if (kiSqrt < minKi) {
        minKi = kiSqrt;
        whereToCutStat = i;
      }
    }

    return whereToCutStat;
  }

  function simpleNormInv(data, options = {}) {
    const {
      magnitudeMode = false
    } = options;
    if (!Array.isArray(data)) data = [data];
    let from = 0;
    let to = 2;
    let step = 0.01;
    let xTraining = createArray(from, to, step);
    let result = new Float64Array(data.length);
    let yTraining = new Float64Array(xTraining.length);

    if (magnitudeMode) {
      let factor = 1;

      for (let i = 0; i < yTraining.length; i++) {
        let finalInput = xTraining[i] * factor;
        yTraining[i] = 1 - rayleighCdf(finalInput);
      }

      let interp = new splineInterpolator(xTraining, yTraining);

      for (let i = 0; i < result.length; i++) {
        let yValue = 2 * data[i];
        result[i] = -1 * interp.interpolate(yValue);
      }
    } else {
      for (let i = 0; i < result.length; i++) {
        result[i] = -1 * Math.SQRT2 * erfcinv(2 * data[i]);
      }
    }

    return result.length === 1 ? result[0] : result;
  }

  function createArray(from, to, step) {
    let result = new Float32Array(Math.abs((from - to) / step + 1));

    for (let i = 0; i < result.length; i++) {
      result[i] = from + i * step;
    }

    return Array.from(result);
  }

  /**
   * This function calculate the norm of a vector
   * @example xNorm([3, 4]) -> 5
   * @param {Array} array - the array that will be rotated
   * @return {number} calculated norm
   */
  function xNorm(array) {
    let result = 0;

    for (let i = 0; i < array.length; i++) {
      result += array[i] ** 2;
    }

    return Math.sqrt(result);
  }

  const toString$7 = Object.prototype.toString;
  function isAnyArray$5(object) {
    return toString$7.call(object).endsWith('Array]');
  }

  /**
   * Checks if input is valdi
   * @param {Array<number>} input

   */

  function xCheck(input) {
    if (!isAnyArray$5(input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }
  }

  /**
   * This function pads an array
   * @param {Array} array - the array that will be padded
   * @param {object} [options={}]
   * @param {string} [options.algorithm=''] '', value, circular, duplicate
   * @param {number} [options.size=0] padding size before first element and after last element
   * @param {number} [options.value=0] value to use for padding (if algorithm='value')
   * @return {Array}
   */

  function xPadding(array, options = {}) {
    const {
      size = 0,
      value = 0,
      algorithm = ''
    } = options;
    xCheck(array);

    if (!algorithm) {
      if (array instanceof Float64Array) {
        return array.slice();
      } else {
        return Float64Array.from(array);
      }
    }

    let result = new Float64Array(array.length + size * 2);

    for (let i = 0; i < array.length; i++) {
      result[i + size] = array[i];
    }

    let fromEnd = size + array.length;
    let toEnd = 2 * size + array.length;

    switch (algorithm.toLowerCase()) {
      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[array.length - 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 Error('xPadding: unknown algorithm');
    }

    return result;
  }

  /**
   * This function performs a circular shift to a new array
   * Positive values of shifts will shift to the right and negative values will do to the left
   * @example xRotate([1,2,3,4],1) -> [4,1,2,3]
   * @example xRotate([1,2,3,4],-1) -> [2,3,4,1]
   * @param {Array} array - the array that will be rotated
   * @param {number} shift
   * @return {Array}
   */
  function xRotate(array, shift) {
    shift = shift % array.length;
    if (shift < 0) shift += array.length;
    let result = new Float64Array(array.length);
    result.set(array.slice(array.length - shift));
    result.set(array.slice(0, array.length - shift), shift);
    return result;
  }

  /**
   * This function calculates a rolling average
   * @param {Array<Number>} array - the array that will be rotated
   * @param {function} fct callback function that from an array returns a value.
   * @param {object} [options={}]
   * @param {number} [options.window=5] rolling window
   * @param {string} [options.padding.size=0] none, value, circular, duplicate
   * @param {string} [options.padding.algorithm='value'] none, value, circular, duplicate
   * @param {number} [options.padding.value=0] value to use for padding (if algorithm='value')
   * @return {Array<Number>}
   */

  function xRolling(array, fct, options = {}) {
    xCheck(array);
    if (typeof fct !== 'function') throw Error('fct has to be a function');
    const {
      window = 5,
      padding = {}
    } = options;
    const {
      size = window - 1,
      algorithm,
      value
    } = padding;
    array = xPadding(array, {
      size,
      algorithm,
      value
    }); // ensure we get a copy and it is float64

    const newArray = [];

    for (let i = 0; i < array.length - window + 1; i++) {
      let subArray = new Float64Array(array.buffer, i * 8, window); // we will send a view to the original buffer

      newArray.push(fct(subArray));
    }

    return newArray;
  }

  const toString$6 = Object.prototype.toString;
  function isAnyArray$4(object) {
    return toString$6.call(object).endsWith('Array]');
  }

  function sum$2(input) {
    if (!isAnyArray$4(input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }

    var sumValue = 0;

    for (var i = 0; i < input.length; i++) {
      sumValue += input[i];
    }

    return sumValue;
  }

  function mean(input) {
    return sum$2(input) / input.length;
  }

  /**
   * This function calculates a rolling average
   * @param {Array<Number>} array - the array that will be rotated
   * @param {object} [options={}]
   * @param {number} [options.window=5] rolling window
   * @param {string} [options.padding.size=window-1] none, value, circular, duplicate
   * @param {string} [options.padding.algorithm=''] none, value, circular, duplicate
   * @param {number} [options.padding.value=0] value to use for padding (if algorithm='value')
   * @return {Array<Number>}
   */

  function xRollingAverage(array, options = {}) {
    return xRolling(array, mean, options);
  }

  /**
   * This function calculates a rolling average
   * @param {Array<Number>} array - the array that will be rotated
   * @param {object} [options={}]
   * @param {number} [options.window=5] rolling window
   * @param {string} [options.padding.size=window-1] none, value, circular, duplicate
   * @param {string} [options.padding.algorithm=''] none, value, circular, duplicate
   * @param {number} [options.padding.value=0] value to use for padding (if algorithm='value')
   * @return {Array<Number>}
   */

  function xRollingMedian(array, options = {}) {
    return xRolling(array, median$2, options);
  }

  /**
   * This function xSubtract the first array by the second array or a constant value from each element of the first array
   * @param {Array} array1 - the array that will be rotated
   * @param {Array|Number} array2
   * @return {Array}
   */
  function xSubtract(array1, array2) {
    let isConstant = false;
    let constant;

    if (Array.isArray(array2)) {
      if (array1.length !== array2.length) {
        throw new Error('sub: size of array1 and array2 must be identical');
      }
    } else {
      isConstant = true;
      constant = Number(array2);
    }

    let array3 = new Array(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;
  }

  /**
   * Computes the index of the minimum of the given values
   * @param {Array<number>} input
   * @return {number}
   */

  function xMinIndex(input) {
    xCheck(input);
    let minIndex = 0;

    for (let i = 1; i < input.length; i++) {
      if (input[i] < input[minIndex]) {
        minIndex = i;
      }
    }

    return minIndex;
  }

  /**
   * Computes the index of the maximum of the given values
   * @param {Array<number>} input
   * @return {number}
   */

  function xMaxIndex(input) {
    xCheck(input);
    let maxIndex = 0;

    for (let i = 1; i < input.length; i++) {
      if (input[i] > input[maxIndex]) {
        maxIndex = i;
      }
    }

    return maxIndex;
  }

  /**
   * Calculates reimAbsolute value of a complex spectrum
   * @param {object} [reim] - An object of kind {re:[], im:[]}.
   * @return {Float64Array}
   */
  function reimAbsolute(data) {
    const length = data.re.length;
    const re = data.re;
    const im = data.im;
    const newArray = new Float64Array(length);

    for (let i = 0; i < length; i++) {
      newArray[i] = Math.sqrt(re[i] ** 2 + im[i] ** 2);
    }

    return newArray;
  }

  /**
   * Phase correction filter
   * @param {object} reim - An object of kind {re:[], im:[]}
   * @param {number} [phi0 = 0] - Angle in radians for zero order phase correction
   * @param {number} [phi1 = 0] - Angle in radians for first order phase correction
   * @return {object} returns a new object {re:[], im:[]}
   */
  function reimPhaseCorrection(data, phi0, phi1) {
    phi0 = Number.isFinite(phi0) ? phi0 : 0;
    phi1 = Number.isFinite(phi1) ? phi1 : 0;
    const re = data.re;
    const im = data.im;
    const length = data.re.length;
    const delta = phi1 / length;
    const alpha = 2 * Math.pow(Math.sin(delta / 2), 2);
    const beta = Math.sin(delta);
    let cosTheta = Math.cos(phi0);
    let sinTheta = Math.sin(phi0);
    const newRe = new Float64Array(length);
    const newIm = new Float64Array(length);

    for (let i = 0; i < length; i++) {
      newRe[i] = re[i] * cosTheta - im[i] * sinTheta;
      newIm[i] = re[i] * sinTheta + im[i] * cosTheta; // calculate angles i+1 from i

      let newCosTheta = cosTheta - (alpha * cosTheta + beta * sinTheta);
      let newSinTheta = sinTheta - (alpha * sinTheta - beta * cosTheta);
      cosTheta = newCosTheta;
      sinTheta = newSinTheta;
    }

    return {
      re: newRe,
      im: newIm
    };
  }

  /**
   * Implementation of the algorithm for automatic phase correction: A robust, general automatic phase
   * correction algorithm for high-resolution NMR data. 10.1002/mrc.4586
   * @param {object} data - { re, im } real and imaginary data.
   * @param {object} options -
   * @param {Number} options.minRegSize - min number of points to auto phase a region.
   * @param {Number} options.maxDistanceToJoin - max distance between regions (in number of points) to join two regions
   * @param {boolean} options.magnitudeMode - if true it uses magnitude spectrum.boolean
   * @param {Number} options.factorNoise - scale the cutoff like factorStd * noiseLevel.
   */

  const defaultOptions = {
    minRegSize: 30,
    maxDistanceToJoin: 256,
    magnitudeMode: true,
    factorNoise: 3
  };
  function reimAutoPhaseCorrection(data, options = {}) {
    const {
      re,
      im
    } = data;
    const length = re.length;
    options = Object.assign(defaultOptions, options);
    const {
      magnitudeMode,
      minRegSize
    } = options;
    let magnitudeData = magnitudeMode ? reimAbsolute(data) : re;
    let ds = holoborodko(magnitudeData);
    let peaksDs = robustBaseLineRegionsDetection(ds, options);
    let peaksSp = robustBaseLineRegionsDetection(magnitudeData, options);
    let finalPeaks = new Array(length);

    for (let i = 0; i < length; i++) {
      finalPeaks[i] = peaksSp[i] & peaksDs[i];
    } // Once the regions are detected, we auto phase each of them separately.
    // TODO: This part can be put inside a function


    let i = -1;
    let x0 = 0;
    let res = [];

    while (i < length) {
      //phase first region
      let reTmp = [];
      let imTmp = []; //Look for the first 1 in the array

      while (!finalPeaks[++i] && i < length) {
        //TODO: Add some extra points(0.1 ppm) at rigth and left sides of the region.
        x0 = i;
      }

      for (; finalPeaks[i] && i < length; i++) {
        reTmp.push(re[i]);
        imTmp.push(im[i]);
        i++;
      }

      if (reTmp.length > minRegSize) {
        res.push(autoPhaseRegion(reTmp, imTmp, x0));
      }
    } // TODO: Still some corrections needed. In the paper they remove the outlayers interatively
    // until they can perform a regression witout bad points. Can someone help here?


    let [ph1, ph0] = weightedLinearRegression(res.map(r => r.x0 / length), res.map(r => r.ph0), res.map(r => r.area / 1e11));
    let phased = reimPhaseCorrection({
      re,
      im
    }, ph0 * Math.PI / 180, ph1 * Math.PI / 180);
    return {
      data: phased,
      ph0,
      ph1
    };
  }

  function autoPhaseRegion(re, im, x0) {
    let start = -180;
    let stop = 180;
    let nSteps = 6;
    let maxSteps = 5;
    let bestAng = 0;
    let minArea = Number.MAX_SAFE_INTEGER;

    while (maxSteps > 0) {
      let dAng = (stop - start) / (nSteps + 1);

      for (let i = start; i <= stop; i += dAng) {
        let phased = reimPhaseCorrection({
          re,
          im
        }, toRadians(i), 0);
        let negArea = getNegArea(phased.re);

        if (negArea < minArea) {
          [minArea, bestAng] = [negArea, i];
        }
      }

      start = bestAng - dAng;
      stop = bestAng + dAng;
      maxSteps--;
    } // Calculate the area for the best angle


    let phased = reimPhaseCorrection({
      re,
      im
    }, toRadians(bestAng), 0);
    let area = 0;
    let sumX = 0;

    for (let j = 0; j < re.length; j++) {
      area += phased.re[j];
      sumX += phased.re[j] * (j + x0);
    }

    return {
      ph0: bestAng,
      area,
      x0: sumX / area
    };
  }

  function holoborodko(s) {
    let dk = new Float64Array(s.length);

    for (let i = 5; i < s.length - 5; i++) {
      dk[i] = (42 * (s[i + 1] - s[i - 1]) + 48 * (s[i + 2] - s[i - 2]) + 27 * (s[i + 3] + s[i - 3]) + 8 * (s[i + 4] - s[i - 4]) + s[i + 5] - s[i - 5]) / 512;
    } //Fill the borders


    for (let i = 0; i < 5; i++) {
      dk[i] = dk[5];
      dk[s.length - i - 1] = dk[s.length - 6];
    }

    return dk;
  }

  function robustBaseLineRegionsDetection(s, options) {
    const {
      maxDistanceToJoin,
      magnitudeMode,
      factorNoise
    } = options;
    let mask = new Array(s.length);

    for (let i = 0; i < s.length; i++) {
      mask[i] = false;
    }

    let change = true;

    while (change) {
      let noiseLevel = xNoiseSanPlot(s, {
        magnitudeMode
      });
      let cutOff = factorNoise * noiseLevel.positive;
      change = false;

      for (let i = 0; i < s.length; i++) {
        if (Math.abs(s[i]) > cutOff && !mask[i]) {
          change = true;
          mask[i] = true;
        }
      }
    } // Clean up mask by merging peaks blocks, separated by just a few points(4??).


    let count = 0;
    let prev = 0;

    for (let i = 0; i < s.length; i++) {
      if (!mask[i]) {
        count++;
      } else {
        if (count < maxDistanceToJoin) {
          for (let j = 0; j <= count; j++) {
            mask[prev + j] = true;
          }
        }

        while (mask[++i] && i < s.length);

        prev = i;
        count = 0;
      }
    }

    return mask;
  }

  function weightedLinearRegression(x, y, w) {
    let sxtw = 0;
    let swx = 0;
    let sw = 0;
    let sxtwy = 0;
    let swy = 0;

    for (let i = 0; i < x.length; i++) {
      sxtw += x[i] * x[i] * w[i];
      swx += x[i] * w[i];
      sw += w[i];
      sxtwy += x[i] * w[i] * y[i];
      swy += w[i] * y[i];
    }
    /* Just to know what is the matrix system that we solve
     let Mx = [[sxtw, swx], [swx, sw]];
     let My = [[sxtwy], [swy]];
    */
    //Mx inverse


    let detMx = sxtw * sw - swx * swx;
    let inMx = [[sw / detMx, -swx / detMx], [-swx / detMx, sxtw / detMx]];
    return [inMx[0][0] * sxtwy + inMx[0][1] * swy, inMx[1][0] * sxtwy + inMx[1][1] * swy];
  }

  const toRadians = degree => degree * Math.PI / 180;

  const getNegArea = data => {
    let area = 0;

    for (let i = 0; i < data.length; i++) {
      if (data[i] < 0) area -= data[i];
    }

    return area;
  };

  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;
  }

  var fft = FFT;

  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;
  };

  function reimFFT(data, options = {}) {
    const {
      inverse = false,
      applyZeroShift = false
    } = options;
    let {
      re,
      im
    } = data;
    const size = re.length;
    const csize = size << 1;
    let complexArray = new Float64Array(csize);

    for (let i = 0; i < csize; i += 2) {
      complexArray[i] = re[i >>> 1];
      complexArray[i + 1] = im[i >>> 1];
    }

    let fft$1 = new fft(size);
    let output = new Float64Array(csize);

    if (inverse) {
      if (applyZeroShift) complexArray = zeroShift(complexArray, true);
      fft$1.inverseTransform(output, complexArray);
    } else {
      fft$1.transform(output, complexArray);
      if (applyZeroShift) output = zeroShift(output);
    }

    let newRe = new Float64Array(size);
    let newIm = new Float64Array(size);

    for (let i = 0; i < csize; i += 2) {
      newRe[i >>> 1] = output[i];
      newIm[i >>> 1] = output[i + 1];
    }

    return {
      re: newRe,
      im: newIm
    };
  }

  const zeroShift = (data, inverse) => {
    let middle = inverse ? Math.ceil(data.length / 2) : Math.floor(data.length / 2);
    return xRotate(data, middle);
  };

  /**
   * This function make a zero filling to re and im part.
   * @param {object} data Object of kind {x:[], re:[], im:[]}.
   * @param {number} totalLength - final number of points
   * @return {SD}
   */
  function xreimZeroFilling(data, totalLength) {
    let length = data.x.length;
    if (totalLength === 0 || length === totalLength) return data;

    if (length > totalLength) {
      return {
        x: data.x.slice(0, totalLength),
        re: data.re.slice(0, totalLength),
        im: data.im.slice(0, totalLength)
      };
    }

    const x = data.x;
    const re = data.re;
    const im = data.im;
    const newX = new Float64Array(totalLength);
    const newRE = new Float64Array(totalLength);
    const newIM = new Float64Array(totalLength);

    for (let i = 0; i < length; i++) {
      newX[i] = x[i];
      newRE[i] = re[i];
      newIM[i] = im[i];
    }

    const deltaX = (x[x.length - 1] - x[0]) / (length - 1);

    for (let i = length; i < totalLength; i++) {
      newX[i] = newX[i - 1] + deltaX;
    }

    return {
      x: newX,
      re: newRE,
      im: newIM
    };
  }

  /**
   * Sort object of array, x has to be monotone.
   * @param {object} data Object of kind {x:[], re:[], im:[]}.
   * @return {SD}
   */
  function xreimSortX(data) {
    const {
      x,
      re,
      im
    } = data;

    if (x.length !== re.length || x.length !== im.length) {
      throw TypeError('xreimSortX: length of x, re and im must be identical');
    }

    if (x.length < 2 || x[0] < x[1]) return data;
    return {
      x: x.slice(0).reverse(),
      re: re.slice(0).reverse(),
      im: im.slice(0).reverse()
    };
  }

  /**
   * xyAligns data of two spectra by verifying wether x values are in a certain range (`delta`).
   * The two spectra should not have two consecutive x values which difference is
   * smaller than `delta` to achieve good results!
   * @param {DataXY} spectrum1 First spectrum data
   * @param {DataXY} spectrum2 Second spectrum data
   * @param {object} options
   * @param {number} [options.delta = 1] The range in which the two x values of the spectra must be to be placed on the same line
   * @param {boolean} [options.common = true] If `true`, only the data considered as common to both spectra is kept. If `false`, the data y arrays are completed with zeroes where no common values are found
   * @param {string} [options.x = 'x1'] Defines what x values should be kept (`x1` : spectrum 1 x values, `x2` spectrum 2 x values, `weighted`: weighted average of both spectra x values)
   * @param {function} [options.weightFunction = undefined] Function that allows to weight `delta` depending on the X values of the spectrum
   */
  function xyAlign(spectrum1, spectrum2, options = {}) {
    const {
      delta = 1,
      common = true,
      x = 'x1',
      weightFunction = undefined
    } = options;
    let result = {
      x: [],
      y1: [],
      y2: []
    };
    let i = 0;
    let j = 0;
    let length1 = spectrum1.x.length;
    let length2 = spectrum2.x.length;

    while (i < spectrum1.x.length && j < spectrum2.x.length) {
      let maxDiff = 0;

      if (typeof weightFunction === 'function') {
        let mean = (spectrum1.x[i] + spectrum2.x[j]) / 2; // is this a good thing to do?

        maxDiff = weightFunction(mean);
      } else {
        maxDiff = delta;
      }

      let difference = spectrum1.x[i] - spectrum2.x[j];

      if (Math.abs(difference) > maxDiff) {
        if (difference > 0) {
          if (!common) {
            result.x.push(spectrum2.x[j]);
            result.y1.push(0);
            result.y2.push(spectrum2.y[j]);

            if (j === length2 - 1) {
              while (i < spectrum1.x.length) {
                result.x.push(spectrum1.x[i]);
                result.y1.push(spectrum1.y[i]);
                result.y2.push(0);
                i++;
              }
            }
          } // console.log({ i, j }, result);


          j++;
        } else {
          if (!common) {
            result.x.push(spectrum1.x[i]);
            result.y1.push(spectrum1.y[i]);
            result.y2.push(0);

            if (i === length1 - 1) {
              while (j < spectrum2.x.length) {
                result.x.push(spectrum2.x[j]);
                result.y1.push(0);
                result.y2.push(spectrum2.y[j]);
                j++;
              }
            }
          } // console.log({ i, j }, result);


          i++;
        }
      } else {
        let weightedX = (spectrum1.x[i] * spectrum1.y[i] + spectrum2.x[j] * spectrum2.y[j]) / (spectrum1.y[i] + spectrum2.y[j]);

        switch (x) {
          case 'x1':
            result.x.push(spectrum1.x[i]);
            break;

          case 'x2':
            result.x.push(spectrum2.x[j]);
            break;

          case 'weighted':
            result.x.push(weightedX);
            break;

          default:
            throw new Error(`Error: Unknown x option value: ${x}`);
        }

        result.y1.push(spectrum1.y[i]);
        result.y2.push(spectrum2.y[j]); // console.log({ i, j }, result);

        i++;
        j++;
      }
    }

    return result;
  }

  /**
   * Throw an error in no an object of x,y arrays
   * @param {DataXY} [data={}]
   */

  function xyCheck(data = {}) {
    if (!isAnyArray$5(data.x) || !isAnyArray$5(data.y)) {
      throw new Error('Points must be an object of x and y arrays');
    }

    if (data.x.length !== data.y.length) {
      throw new Error('The x and y arrays mush have the same length');
    }
  }

  /**
   * Normalize an array of zones:
   * - ensure than from < to
   * - merge overlapping zones
   * @param {Array<Zone>} [zones=[]]
   * @param {object} [options={}]
   * @param {number} [options.from=Number.MIN_VALUE]
   * @param {number} [options.to=Number.MAX_VALUE]
   */
  function zonesNormalize(zones = [], options = {}) {
    if (zones.length === 0) return [];
    zones = JSON.parse(JSON.stringify(zones)).map(zone => zone.from > zone.to ? {
      from: zone.to,
      to: zone.from
    } : zone);
    let {
      from = Number.NEGATIVE_INFINITY,
      to = Number.POSITIVE_INFINITY
    } = options;

    if (from > to) {
      [from, to] = [to, from];
    }

    zones = zones.sort((a, b) => {
      if (a.from !== b.from) return a.from - b.from;
      return a.to - b.to;
    });
    zones.forEach(zone => {
      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];
    let result = [currentZone];

    for (let zone of zones) {
      if (zone.from <= currentZone.to) {
        currentZone.to = zone.to;
      } else {
        currentZone = zone;
        result.push(currentZone);
      }
    }

    return result;
  }

  /**
   * xyExtract zones from a XY data
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {Array} [options.zones=[]]
   * @return {Array} Array of points
   */

  function xyExtract(data = {}, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    let {
      zones
    } = options;
    zones = zonesNormalize(zones);
    if (!Array.isArray(zones) || zones.length === 0) return data;
    let newX = [];
    let newY = [];
    let currentZone = zones[0];
    let position = 0;

    loop: for (let i = 0; i < x.length; i++) {
      while (currentZone.to < x[i]) {
        position++;
        currentZone = zones[position];

        if (!currentZone) {
          i = x.length;
          break loop;
        }
      }

      if (x[i] >= currentZone.from) {
        newX.push(x[i]);
        newY.push(y[i]);
      }
    }

    return {
      x: newX,
      y: newY
    };
  }

  /**
   * Returns the numberMaxPoints points with the bigger y.
   * @param {DataXY} data - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {number} numberMaxPoints Number of points to keep
   * @returns {object} The points filtered to keep the `numberMaxPoints` most intense points of the input
   */

  function xyGetNMaxY(data, numberMaxPoints) {
    xyCheck(data);

    if (data.x.length <= numberMaxPoints) {
      return data;
    } else {
      let newX = new Array(numberMaxPoints);
      let newY = new Array(numberMaxPoints); // slice() is used to make a copy of the array, because sort() is IPM

      let threshold = data.y.slice().sort((a, b) => b - a)[numberMaxPoints - 1];
      let index = 0;

      for (let i = 0; i < data.x.length; i++) {
        if (data.y[i] >= threshold) {
          newX[index] = data.x[i];
          newY[index] = data.y[i];
          index++;
        }

        if (index === numberMaxPoints) {
          return {
            x: newX,
            y: newY
          };
        }
      }
    }
  }

  /**
   * Order object of array, x has to be monotone.
   * Ensure x is growing
   * @param {DataXY} data Object of kind {x:[], y:[]}.
   * @return {SD}
   */
  function xyGrowingX(data) {
    const {
      x,
      y
    } = data;

    if (x.length !== y.length) {
      throw TypeError('sortX: length of x and y must be identical');
    }

    if (x.length < 2 || x[0] < x[1]) return data;
    return {
      x: x.slice(0).reverse(),
      y: y.slice(0).reverse()
    };
  }

  /**
   * Generate a X / Y of the xyIntegral
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.from] - First value for xyIntegration in the X scale
   * @param {number} [options.fromIndex=0] - First point for xyIntegration
   * @param {number} [options.to] - Last value for xyIntegration in the X scale
   * @param {number} [options.toIndex=x.length-1] - Last point for xyIntegration
   * @param {boolean} [options.reverse=false] - Integrate from the larger value to the smallest value
   * @return {{x:[],y:[]}} An object with the xyIntegration function
   */

  function xyIntegral(data = {}, options = {}) {
    const {
      reverse = false
    } = options;
    xyCheck(data);
    const {
      x,
      y
    } = data;
    if (x.length < 2) return 0;
    const {
      fromIndex,
      toIndex
    } = xGetFromToIndex(x, options);
    let xyIntegration = 0;
    let currentxyIntegral;

    if (reverse) {
      currentxyIntegral = {
        x: [x[toIndex]],
        y: [0]
      };

      for (let i = toIndex; i > fromIndex; i--) {
        xyIntegration += (x[i] - x[i - 1]) * (y[i - 1] + y[i]) / 2;
        currentxyIntegral.x.push(x[i - 1]);
        currentxyIntegral.y.push(xyIntegration);
      }

      currentxyIntegral.x.reverse();
      currentxyIntegral.y.reverse();
    } else {
      currentxyIntegral = {
        x: [x[fromIndex]],
        y: [0]
      };

      for (let i = fromIndex; i < toIndex; i++) {
        xyIntegration += (x[i + 1] - x[i]) * (y[i + 1] + y[i]) / 2;
        currentxyIntegral.x.push(x[i + 1]);
        currentxyIntegral.y.push(xyIntegration);
      }
    }

    return currentxyIntegral;
  }

  /**
   * In place modification of the 2 arrays to make X unique and sum the Y if X has the same value
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.from] - First value for xyIntegration in the X scale
   * @param {number} [options.fromIndex=0] - First point for xyIntegration
   * @param {number} [options.to] - Last value for xyIntegration in the X scale
   * @param {number} [options.toIndex=x.length-1] - Last point for xyIntegration
   * @return {number} xyIntegration value on the specified range
   */

  function xyIntegration(data = {}, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    if (x.length < 2) return 0;
    const {
      fromIndex,
      toIndex
    } = xGetFromToIndex(x, options);
    let currentxyIntegration = 0;

    for (let i = fromIndex; i < toIndex; i++) {
      currentxyIntegration += (x[i + 1] - x[i]) * (y[i + 1] + y[i]) / 2;
    }

    return currentxyIntegration;
  }

  /**
   * Find the closest maximum going up hill
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.target]
   * @param {number} [options.targetIndex=0]
   * @return {{x,y,xIndex}} An object with the x/y value
   */

  function xyMaxClosestYPoint(data, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    let {
      target,
      targetIndex
    } = options;

    if (targetIndex === undefined) {
      if (target !== undefined) {
        targetIndex = xFindClosestIndex$1(x, target);
      } else {
        targetIndex = 0;
      }
    }

    let previousIndex = Number.MIN_SAFE_INTEGER;
    let currentIndex = targetIndex;
    let xyMaxY = y[targetIndex];

    while (currentIndex !== previousIndex) {
      previousIndex = currentIndex;

      if (currentIndex > 0 && y[currentIndex - 1] > xyMaxY) {
        currentIndex--;
      } else if (currentIndex < x.length - 1 && y[currentIndex + 1] > xyMaxY) {
        currentIndex++;
      }

      xyMaxY = y[currentIndex];
    }

    return {
      x: x[currentIndex],
      y: y[currentIndex],
      index: currentIndex
    };
  }

  /**
   * Finds the max value in a zone
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.from] - First value for xyIntegration in the X scale
   * @param {number} [options.fromIndex=0] - First point for xyIntegration
   * @param {number} [options.to] - Last value for xyIntegration in the X scale
   * @param {number} [options.toIndex=x.length-1] - Last point for xyIntegration
   * @return {number} Max y on the specified range
   */

  function xyMaxY(data = {}, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    if (x.length < 2) return 0;
    const {
      fromIndex,
      toIndex
    } = xGetFromToIndex(x, options);
    let currentxyMaxY = y[fromIndex];

    for (let i = fromIndex; i <= toIndex; i++) {
      if (y[i] > currentxyMaxY) currentxyMaxY = y[i];
    }

    return currentxyMaxY;
  }

  /**
   * Finds the max y value in a range and return a {x,y} point
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.from] - First value for xyIntegration in the X scale
   * @param {number} [options.fromIndex=0] - First point for xyIntegration
   * @param {number} [options.to] - Last value for xyIntegration in the X scale
   * @param {number} [options.toIndex=x.length-1] - Last point for xyIntegration
   * @return {object}
   */

  function xyMaxYPoint(data = {}, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    if (x.length < 2) return 0;
    const {
      fromIndex,
      toIndex
    } = xGetFromToIndex(x, options);
    let current = {
      x: x[fromIndex],
      y: y[fromIndex],
      index: fromIndex
    };

    for (let i = fromIndex; i <= toIndex; i++) {
      if (y[i] > current.y) current = {
        x: x[i],
        y: y[i],
        index: i
      };
    }

    return current;
  }

  /**
   * Finds all the max values
   * If the values are equal the middle
   * of the equal part will be the position of the signal!
   *
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @return {Array} Array of points
   */

  function xyMaximaY(data = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    if (x.length < 3) return [];
    let maxima = [];
    let startEqualIndex = -1;

    for (let i = 1; i < x.length - 1; i++) {
      if (y[i - 1] < y[i] && y[i + 1] < y[i]) {
        maxima.push({
          x: x[i],
          y: y[i],
          index: i
        });
      } else if (y[i - 1] < y[i] && y[i + 1] === y[i]) {
        startEqualIndex = i;
      } else if (y[i - 1] === y[i] && y[i + 1] < y[i]) {
        let index = (i + startEqualIndex) / 2 >> 0;
        maxima.push({
          x: x[index],
          y: y[index],
          index
        });
      }
    }

    return maxima;
  }

  /**
   * Find the closest minimum going down hill
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.target]
   * @param {number} [options.targetIndex=0]
   * @return {{x,y,xIndex}} An object with the x/y value
   */

  function xyMinClosestYPoint(data, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    let {
      target,
      targetIndex
    } = options;

    if (targetIndex === undefined) {
      if (target !== undefined) {
        targetIndex = xFindClosestIndex$1(x, target);
      } else {
        targetIndex = 0;
      }
    }

    let previousIndex = Number.MIN_SAFE_INTEGER;
    let currentIndex = targetIndex;
    let minY = y[targetIndex];

    while (currentIndex !== previousIndex) {
      previousIndex = currentIndex;

      if (currentIndex > 0 && y[currentIndex - 1] < minY) {
        currentIndex--;
      } else if (currentIndex < x.length - 1 && y[currentIndex + 1] < minY) {
        currentIndex++;
      }

      minY = y[currentIndex];
    }

    return {
      x: x[currentIndex],
      y: y[currentIndex],
      index: currentIndex
    };
  }

  /**
   * Finds the max y value in a range and return a {x,y} point
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.from] - First value for xyIntegration in the X scale
   * @param {number} [options.fromIndex=0] - First point for xyIntegration
   * @param {number} [options.to] - Last value for xyIntegration in the X scale
   * @param {number} [options.toIndex=x.length-1] - Last point for xyIntegration
   * @return {object}
   */

  function xyMinYPoint(data = {}, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    if (x.length < 2) return 0;
    const {
      fromIndex,
      toIndex
    } = xGetFromToIndex(x, options);
    let current = {
      x: x[fromIndex],
      y: y[fromIndex],
      index: fromIndex
    };

    for (let i = fromIndex; i <= toIndex; i++) {
      if (y[i] < current.y) current = {
        x: x[i],
        y: y[i],
        index: i
      };
    }

    return current;
  }

  /**
   * Finds all the min values
   * If the values are equal the middle
   * of the equal part will be the position of the signal!
   *
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @return {Array} Array of points
   */

  function xyMinimaY(data = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    if (x.length < 3) return [];
    let maxima = [];
    let startEqualIndex = -1;

    for (let i = 1; i < x.length - 1; i++) {
      if (y[i - 1] > y[i] && y[i + 1] > y[i]) {
        maxima.push({
          x: x[i],
          y: y[i],
          index: i
        });
      } else if (y[i - 1] > y[i] && y[i + 1] === y[i]) {
        startEqualIndex = i;
      } else if (y[i - 1] === y[i] && y[i + 1] > y[i]) {
        let index = (i + startEqualIndex) / 2 >> 0;
        maxima.push({
          x: x[index],
          y: y[index],
          index
        });
      }
    }

    return maxima;
  }

  /**
   * Returns an information about a signal
   *
   * We expect ordered data and equidistant X axis
   * You can use the method helper if required:
   * ML.ArrayPoints.uniqueX
   * ML.ArrayPoints.sortX
   * ML.ArrayPoints.equallySpaced
   *
   * @param {object} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.target]
   * @param {number} [options.targetIndex]
   * @return {object} Information about signal
   */

  function xyPeakInfo(data = {}, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    if (x.length < 3) return undefined;
    let {
      targetIndex,
      target
    } = options;

    if (targetIndex === undefined) {
      if (target !== undefined) {
        targetIndex = xFindClosestIndex$1(x, target);
      }
    }

    if (targetIndex === undefined) {
      throw new Error('xyPeakInfo: need to specify target or targetIndex');
    }

    let i = targetIndex;
    let currentDiff = y[i] - y[i + 1];
    let multiplier = currentDiff < 0 ? -1 : 1;
    currentDiff *= multiplier;

    while (i < x.length - 1) {
      i++;
      let newDiff = (y[i] - y[i + 1]) * multiplier;
      if (newDiff < currentDiff) break;
      currentDiff = newDiff;
    }

    let after = {
      x: x[i],
      y: y[i]
    };
    i = targetIndex;
    currentDiff = (y[i] - y[i - 1]) * multiplier;

    while (i > 1) {
      i--;
      let newDiff = (y[i] - y[i - 1]) * multiplier;
      if (newDiff < currentDiff) break;
      currentDiff = newDiff;
    }

    let before = {
      x: x[i],
      y: y[i]
    };
    return {
      inflectionBefore: before,
      inflectionAfter: after,
      extrema: {
        x: x[targetIndex],
        y: y[targetIndex]
      },
      inflectionMiddle: {
        x: (before.x + after.x) / 2,
        y: (before.y + after.y) / 2
      },
      width: Math.abs(before.x - after.x)
    };
  }

  /**
   * Find the closest minimum going down hill
   * @param {object} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.target]
   * @param {number} [options.targetIndex=0]
   * @return {{x,y,xIndex}} An object with the x/y value
   */

  function xyRealMaxYPoint(data, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    const targetIndex = xGetTargetIndex(x, options); // interpolation to a sin() function

    if (y[targetIndex - 1] > 0 && y[targetIndex + 1] > 0 && y[targetIndex] >= y[targetIndex - 1] && y[targetIndex] >= y[targetIndex + 1]) {
      let alpha = 20 * Math.log10(y[targetIndex - 1]);
      let beta = 20 * Math.log10(y[targetIndex]);
      let gamma = 20 * Math.log10(y[targetIndex + 1]);
      let p = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma);
      return {
        x: x[targetIndex] + (x[targetIndex] - x[targetIndex - 1]) * p,
        y: y[targetIndex] - 0.25 * (y[targetIndex - 1] - y[targetIndex + 1]) * p,
        index: targetIndex
      };
    } else {
      return {
        x: x[targetIndex],
        y: y[targetIndex],
        index: targetIndex
      };
    }
  }

  function xyRealMinYPoint(data, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    const targetIndex = xGetTargetIndex(x, options); // interpolation to a sin() function

    if (y[targetIndex - 1] < 0 && y[targetIndex + 1] < 0 && y[targetIndex] <= y[targetIndex - 1] && y[targetIndex] <= y[targetIndex + 1]) {
      let alpha = 20 * Math.log10(-y[targetIndex - 1]);
      let beta = 20 * Math.log10(-y[targetIndex]);
      let gamma = 20 * Math.log10(-y[targetIndex + 1]);
      let p = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma);
      return {
        x: x[targetIndex] + (x[targetIndex] - x[targetIndex - 1]) * p,
        y: y[targetIndex] - 0.25 * (y[targetIndex - 1] - y[targetIndex + 1]) * p,
        index: targetIndex
      };
    } else {
      return {
        x: x[targetIndex],
        y: y[targetIndex],
        index: targetIndex
      };
    }
  }

  /**
   * xyReduce the number of points while keeping visually the same noise. Practical to
   * display many spectra as SVG.
   * SHOULD NOT BE USED FOR DATA PROCESSING !!!
   * You should rather use ml-xy-equally-spaced to make further processing
   * @param {DataXY} [data={}] - Object that contains property x (an ordered increasing array) and y (an array)
   * @param {object} [options={}]
   * @param {number} [options.from=x[0]]
   * @param {number} [options.to=x[x.length-1]]
   * @param {number} [options.nbPoints=4001] Number of points
   * @param {number} [options.zones=[]] Array of zones to keep (from/to object)
   * @param {number} [options.optimize=false] If optimize we may have less than nbPoints at the end
   */

  function xyReduce(data, options = {}) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    let {
      from = x[0],
      to = x[x.length - 1],
      nbPoints = 4001,
      optimize = false,
      zones = []
    } = options;
    zones = zonesNormalize(zones, {
      from,
      to
    });
    if (zones.length === 0) zones = [{
      from,
      to
    }]; // we take everything
    // for each zone we should know the first index, the last index and the number of points

    let totalPoints = 0;

    for (let zone of zones) {
      zone.fromIndex = xFindClosestIndex$1(x, zone.from);
      zone.toIndex = xFindClosestIndex$1(x, zone.to);

      if (zone.fromIndex > 0 && x[zone.fromIndex] > zone.from) {
        zone.fromIndex--;
      }

      if (zone.toIndex < x.length - 1 && x[zone.toIndex] < zone.to) {
        zone.toIndex++;
      }

      zone.nbPoints = zone.toIndex - zone.fromIndex + 1;
      totalPoints += zone.nbPoints;
    } // we calculate the number of points per zone that we should keep


    if (totalPoints > nbPoints) {
      // need to xyReduce number of points
      let ratio = nbPoints / totalPoints;
      let currentTotal = 0;

      for (let i = 0; i < zones.length - 1; i++) {
        const zone = zones[i];
        zone.nbPoints = Math.round(zone.nbPoints * ratio);
        currentTotal += zone.nbPoints;
      }

      zones[zones.length - 1].nbPoints = nbPoints - currentTotal;
    } else {
      let newX = new Float64Array(totalPoints);
      let newY = new Float64Array(totalPoints);
      let index = 0;

      for (let zone of zones) {
        for (let i = zone.fromIndex; i < zone.toIndex + 1; i++) {
          newX[index] = x[i];
          newY[index] = y[i];
          index++;
        }
      }

      return {
        x: newX,
        y: newY
      };
    }

    let newX = [];
    let newY = [];

    for (let zone of zones) {
      if (!zone.nbPoints) continue;
      appendFromTo(zone.fromIndex, zone.toIndex, zone.nbPoints);
    }

    return {
      x: newX,
      y: newY
    };

    function appendFromTo(fromIndex, toIndex, zoneNbPoints) {
      if (zoneNbPoints === 1) {
        newX.push(x[Math.round((toIndex - fromIndex) / 2)]);
        newY.push(y[Math.round((toIndex - fromIndex) / 2)]);
        return;
      }

      if (zoneNbPoints === 2) {
        newX.push(x[fromIndex], x[toIndex]);
        newY.push(y[fromIndex], y[toIndex]);
        return;
      }

      newX.push(x[fromIndex]);
      newY.push(y[fromIndex]);
      let minY = Number.MAX_VALUE;
      let xyMaxY = Number.MIN_VALUE;

      if (zoneNbPoints % 2 === 0) {
        zoneNbPoints = zoneNbPoints / 2 + 1;
      } else {
        zoneNbPoints = (zoneNbPoints - 1) / 2 + 1;
      } // we will need to make some kind of min / max because there are too many points
      // we will always keep the first point and the last point


      let slot = (x[toIndex] - x[fromIndex]) / (zoneNbPoints - 1);
      let currentX = x[fromIndex] + slot;
      let first = true;

      for (let i = fromIndex + 1; i <= toIndex; i++) {
        if (first) {
          minY = y[i];
          xyMaxY = y[i];
          first = false;
        } else {
          if (y[i] < minY) minY = y[i];
          if (y[i] > xyMaxY) xyMaxY = y[i];
        }

        if (x[i] >= currentX || i === toIndex) {
          if (optimize) {
            if (minY > newY[newX.length - 1]) ; else if (xyMaxY < newY[newX.length - 1]) {
              // we can skip the intermediate value
              xyMaxY = minY;
            } else {
              newX.push(currentX - slot / 2);
              newY.push(minY);
            }
          } else {
            newX.push(currentX - slot / 2);
            newY.push(minY);
          }

          newX.push(currentX);
          newY.push(xyMaxY);
          currentX += slot;
          first = true;
        }
      }
    }
  }

  /**
   * This function calculates a rolling average
   *
   * This methods will recalculate the x values by using xRollingAverage
   * @param {ArrayPoints} [points] array of points {x,y}
   * @param {object} [options={}]
   * @param {number} [options.window=5] rolling window
   * @param {function} [fct] callback function that from an array returns a value.
   * @param {string} [options.padding.size=0] none, value, circular, duplicate
   * @param {string} [options.padding.algorithm='value'] none, value, circular, duplicate
   * @param {number} [options.padding.value=0] value to use for padding (if algorithm='value')
   * @return {Array<Number>}
   */

  function xyRolling(points, fct, options = {}) {
    let {
      x,
      y
    } = points;
    y = xRolling(y, fct, options);

    if (x.length !== y.length) {
      x = xRollingAverage(x, options);
    }

    return {
      x,
      y
    };
  }

  /**
   *
   * @param {DataXY} [data] array of points {x,y}
   * @returns {DataPoints}
   */

  function xyToXYObject(data) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    let objectArray = [];

    for (let i = 0; i < x.length; i++) {
      objectArray.push({
        x: x[i],
        y: y[i]
      });
    }

    return objectArray;
  }

  /**
   * Convert a DataXY to an array of array containing x,y
   * @param {DataXY} [data] array of points {x,y}
   * @returns {Array<Array<number,number>>}
   */

  function xyToXYArray(data) {
    xyCheck(data);
    const {
      x,
      y
    } = data;
    let objectArray = [];

    for (let i = 0; i < x.length; i++) {
      objectArray.push([x[i], y[i]]);
    }

    return objectArray;
  }

  const GAUSSIAN_EXP_FACTOR$1 = -4 * Math.LN2;
  const ROOT_PI_OVER_LN2$1 = Math.sqrt(Math.PI / Math.LN2);
  const ROOT_THREE$1 = Math.sqrt(3);
  const ROOT_2LN2$1 = Math.sqrt(2 * Math.LN2);
  const ROOT_2LN2_MINUS_ONE$1 = Math.sqrt(2 * Math.LN2) - 1;

  // https://en.wikipedia.org/wiki/Error_function#Inverse_functions
  // This code yields to a good approximation
  // If needed a better implementation using polynomial can be found on https://en.wikipedia.org/wiki/Error_function#Inverse_functions
  function erfinv$1(x) {
    let a = 0.147;
    if (x === 0) return 0;
    let ln1MinusXSqrd = Math.log(1 - x * x);
    let lnEtcBy2Plus2 = ln1MinusXSqrd / 2 + 2 / (Math.PI * a);
    let firstSqrt = Math.sqrt(lnEtcBy2Plus2 ** 2 - ln1MinusXSqrd / a);
    let secondSqrt = Math.sqrt(firstSqrt - lnEtcBy2Plus2);
    return secondSqrt * (x > 0 ? 1 : -1);
  }

  class Gaussian$1 {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=4*LN2/(PI*FWHM)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.sd] - Standard deviation, if it's defined options.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      this.fwhm = options.sd ? Gaussian$1.widthToFWHM(2 * options.sd) : options.fwhm ? options.fwhm : 500;
      this.height = options.height === undefined ? Math.sqrt(-GAUSSIAN_EXP_FACTOR$1 / Math.PI) / this.fwhm : options.height;
    }
    /**
     * Calculate a gaussian shape
     * @param {object} [options = {}]
     * @param {number} [options.factor = 6] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {number} [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return {Float64Array} y values
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.min(Math.ceil(this.fwhm * factor), Math.pow(2, 25) - 1);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      const data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a gaussian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @returns {number} - the y value of gaussian with the current parameters.
     */


    fct(x) {
      return Gaussian$1.fct(x, this.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999]
     * @returns {number}
     */


    getFactor(area = 0.9999) {
      return Gaussian$1.getFactor(area);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return Gaussian$1.getArea(this.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
     * //https://mathworld.wolfram.com/GaussianFunction.html
     * @param {number} width - Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      //https://mathworld.wolfram.com/GaussianFunction.html
      return Gaussian$1.widthToFWHM(width);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/GaussianFunction.html
     * @param {number} fwhm - Full Width at Half Maximum.
     * @returns {number} width
     */


    fwhmToWidth(fwhm = this.fwhm) {
      return Gaussian$1.fwhmToWidth(fwhm);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  Gaussian$1.fct = function fct(x, fwhm = 500) {
    return Math.exp(GAUSSIAN_EXP_FACTOR$1 * Math.pow(x / fwhm, 2));
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
   * //https://mathworld.wolfram.com/GaussianFunction.html
   * @param {number} width - Width between the inflection points
   * @returns {number} fwhm
   */


  Gaussian$1.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_2LN2$1;
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/GaussianFunction.html
   * @param {number} fwhm - Full Width at Half Maximum.
   * @returns {number} width
   */


  Gaussian$1.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_2LN2$1;
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {object} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Gaussian$1.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1
    } = options;
    return height * ROOT_PI_OVER_LN2$1 * fwhm / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage.
   * @param {number} [area=0.9999]
   * @returns {number}
   */


  Gaussian$1.getFactor = function getFactor(area = 0.9999) {
    return Math.sqrt(2) * erfinv$1(area);
  };

  class Lorentzian$1 {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=2/(PI*FWHM)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.sd] - Standard deviation, if it's defined options.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      this.fwhm = options.fwhm === undefined ? 500 : options.fwhm;
      this.height = options.height === undefined ? 2 / Math.PI / this.fwhm : options.height;
    }
    /**
     * Calculate a lorentzian shape
     * @param {object} [options = {}]
     * @param {number} [options.factor = Math.tan(Math.PI * (0.9999 - 0.5))] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {number} [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return {Float64Array} y values
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.min(Math.ceil(this.fwhm * factor), Math.pow(2, 25) - 1);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      const data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a lorentzian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @returns {number} - the y value of lorentzian with the current parameters.
     */


    fct(x) {
      return Lorentzian$1.fct(x, this.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999]
     * @returns {number}
     */


    getFactor(area = 0.9999) {
      return Lorentzian$1.getFactor(area);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return Lorentzian$1.getArea(this.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of width between the inflection points of a specific shape from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/LorentzianFunction.html
     * @param {number} [fwhm] - Full Width at Half Maximum.
     * @returns {number} width between the inflection points
     */


    fwhmToWidth(fwhm = this.fwhm) {
      return Lorentzian$1.fwhmToWidth(fwhm);
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) of a specific shape from the width between the inflection points.
     * //https://mathworld.wolfram.com/LorentzianFunction.html
     * @param {number} [width] Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      return Lorentzian$1.widthToFWHM(width);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  Lorentzian$1.fct = function fct(x, fwhm) {
    const squareFWHM = fwhm * fwhm;
    return squareFWHM / (4 * Math.pow(x, 2) + squareFWHM);
  };
  /**
   * Compute the value of width between the inflection points of a specific shape from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/LorentzianFunction.html
   * @param {number} [fwhm] - Full Width at Half Maximum.
   * @returns {number} width between the inflection points
   */


  Lorentzian$1.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_THREE$1;
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) of a specific shape from the width between the inflection points.
   * //https://mathworld.wolfram.com/LorentzianFunction.html
   * @param {number} [width] Width between the inflection points
   * @returns {number} fwhm
   */


  Lorentzian$1.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_THREE$1;
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {*} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Lorentzian$1.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1
    } = options;
    return height * Math.PI * fwhm / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage
   * @param {number} [area=0.9999]
   * @returns {number}
   */


  Lorentzian$1.getFactor = function getFactor(area = 0.9999) {
    return 2 * Math.tan(Math.PI * (area - 0.5));
  };

  class PseudoVoigt$1 {
    /**
     * @param {object} [options={}]
     * @param {number} [options.height=1/(mu*FWHM/sqrt(4*LN2/PI)+(1-mu)*fwhm*PI*0.5)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm=500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.mu=0.5] - ratio of gaussian contribution.
     */
    constructor(options = {}) {
      this.mu = options.mu === undefined ? 0.5 : options.mu;
      this.fwhm = options.fwhm === undefined ? 500 : options.fwhm;
      this.height = options.height === undefined ? 1 / (this.mu / Math.sqrt(-GAUSSIAN_EXP_FACTOR$1 / Math.PI) * this.fwhm + (1 - this.mu) * this.fwhm * Math.PI / 2) : options.height;
    }
    /**
     * Calculate a linear combination of gaussian and lorentzian function width an same full width at half maximum
     * @param { object } [options = {}]
     * @param { number } [options.factor = 2 * Math.tan(Math.PI * (0.9999 - 0.5))] - Number of time to take fwhm in the calculation of the length.Default covers 99.99 % of area.
     * @param { number } [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return { object } - { fwhm, data<Float64Array>} - An with the number of points at half maximum and the array of y values covering the 99.99 % of the area.
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.ceil(this.fwhm * factor);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      let data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a linear combination of Gaussian and Lorentzian shapes where the full width at half maximum are the same for both kind of shapes (see README for equation).
     * @param {number} [x] x value to calculate.
     * @returns {number} - the y value of a pseudo voigt with the current parameters.
     */


    fct(x) {
      return PseudoVoigt$1.fct(x, this.fwhm, this.mu);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999] - required area to be coverage
     * @param {number} [mu=this.mu] - ratio of gaussian contribution.
     * @returns {number}
     */


    getFactor(area = 0.9999, mu = this.mu) {
      return PseudoVoigt$1.getFactor(area, mu);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return PseudoVoigt$1.getArea(this.fwhm, {
        height: this.height,
        mu: this.mu
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FMHM) from width between the inflection points.
     * @param {number} width - width between the inflection points
     * @param {number} [mu = 0.5] - ratio of gaussian contribution.
     * @returns {number} Full Width at Half Maximum (FMHM).
     */


    widthToFWHM(width, mu) {
      return PseudoVoigt$1.widthToFWHM(width, mu);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * @param {number} fwhm - Full Width at Half Maximum.
     * @param {number} [mu] - ratio of gaussian contribution.
     * @returns {number} width between the inflection points.
     */


    fwhmToWidth(fwhm = this.fwhm, mu = this.mu) {
      return PseudoVoigt$1.fwhmToWidth(fwhm, mu);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }
    /**
     * set a new mu
     * @param {number} mu - ratio of gaussian contribution.
     */


    setMu(mu) {
      this.mu = mu;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @param {number} [mu=0.5] - ratio of gaussian contribution.
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  PseudoVoigt$1.fct = function fct(x, fwhm, mu = 0.5) {
    return (1 - mu) * Lorentzian$1.fct(x, fwhm) + mu * Gaussian$1.fct(x, fwhm);
  };
  /**
   * Compute the value of Full Width at Half Maximum (FMHM) from width between the inflection points.
   * @param {number} width - width between the inflection points
   * @param {number} [mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} Full Width at Half Maximum (FMHM).
   */


  PseudoVoigt$1.widthToFWHM = function widthToFWHM(width, mu = 0.5) {
    return width * (mu * ROOT_2LN2_MINUS_ONE$1 + 1);
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * @param {number} fwhm - Full Width at Half Maximum.
   * @param {number} [mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} width between the inflection points.
   */


  PseudoVoigt$1.fwhmToWidth = function fwhmToWidth(fwhm, mu = 0.5) {
    return fwhm / (mu * ROOT_2LN2_MINUS_ONE$1 + 1);
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {*} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @param {number} [options.mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  PseudoVoigt$1.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1,
      mu = 0.5
    } = options;
    return fwhm * height * (mu * ROOT_PI_OVER_LN2$1 + (1 - mu) * Math.PI) / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage
   * @param {number} [area=0.9999] - required area to be coverage
   * @param {number} [mu=this.mu] - ratio of gaussian contribution.
   * @returns {number}
   */


  PseudoVoigt$1.getFactor = function getFactor(area = 0.9999, mu = 0.5) {
    return mu < 1 ? Lorentzian$1.getFactor(area) : Gaussian$1.getFactor(area);
  };

  let axis$1 = ['x', 'y'];
  class Gaussian2D$1 {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=4*LN2/(PI*xFWHM*yFWHM)] Define the height of the peak, by default area=1 (normalized).
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM used if x or y has not the fwhm property.
     * @param {object} [options.x] - Options for x axis.
     * @param {number} [options.x.fwhm = fwhm] - Full Width at Half Maximum in the number of points in FWHM for x axis.
     * @param {number} [options.x.sd] - Standard deviation for x axis, if it's defined options.x.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     * @param {object} [options.y] - Options for y axis.
     * @param {number} [options.y.fwhm = fwhm] - Full Width at Half Maximum in the number of points in FWHM for y axis.
     * @param {number} [options.y.sd] - Standard deviation for y axis, if it's defined options.y.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      let {
        fwhm: globalFWHM = 500
      } = options;

      for (let i of axis$1) {
        let fwhm;

        if (!options[i]) {
          fwhm = globalFWHM;
        } else {
          fwhm = options[i].sd ? Gaussian2D$1.widthToFWHM(2 * options[i].sd) : options[i].fwhm || globalFWHM;
        }

        this[i] = {
          fwhm
        };
      }

      this.height = options.height === undefined ? -GAUSSIAN_EXP_FACTOR$1 / Math.PI / this.x.fwhm / this.y.fwhm : options.height;
    }
    /**
     * Calculate a Gaussian2D shape
     * @param {object} [options = {}]
     * @param {number} [options.factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {object} [options.x] - parameter for x axis.
     * @param {number} [options.x.length=fwhm*factor+1] - length on x axis.
     * @param {number} [options.x.factor=factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {object} [options.y] - parameter for y axis.
     * @param {number} [options.y.length=fwhm*factor+1] - length on y axis.
     * @param {number} [options.y.factor=factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @return {Array<Float64Array>} - z values.
     */


    getData(options = {}) {
      let {
        x = {},
        y = {},
        factor = this.getFactor(),
        length
      } = options;
      let xLength = x.length || length;

      if (!xLength) {
        let {
          factor: xFactor = factor
        } = x;
        xLength = Math.min(Math.ceil(this.x.fwhm * xFactor), Math.pow(2, 25) - 1);
        if (xLength % 2 === 0) xLength++;
      }

      let yLength = y.length || length;

      if (!yLength) {
        let {
          factor: yFactor = factor
        } = y;
        yLength = Math.min(Math.ceil(this.y.fwhm * yFactor), Math.pow(2, 25) - 1);
        if (yLength % 2 === 0) yLength++;
      }

      const xCenter = (xLength - 1) / 2;
      const yCenter = (yLength - 1) / 2;
      const data = new Array(xLength);

      for (let i = 0; i < xLength; i++) {
        data[i] = new Array(yLength);
      }

      for (let i = 0; i < xLength; i++) {
        for (let j = 0; j < yLength; j++) {
          data[i][j] = this.fct(i - xCenter, j - yCenter) * this.height;
        }
      }

      return data;
    }
    /**
     * Return the intensity value of a 2D gaussian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @param {number} y - y value to calculate.
     * @returns {number} - the z value of bi-dimensional gaussian with the current parameters.
     */


    fct(x, y) {
      return Gaussian2D$1.fct(x, y, this.x.fwhm, this.y.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific volume coverage.
     * @param {number} [volume=0.9999]
     * @returns {number}
     */


    getFactor(volume = 0.9999) {
      return Gaussian2D$1.getFactor(volume);
    }
    /**
     * Calculate the volume of the shape.
     * @returns {number} - returns the volume.
     */


    getVolume() {
      return Gaussian2D$1.getVolume(this.x.fwhm, this.y.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
     * //https://mathworld.wolfram.com/Gaussian2DFunction.html
     * @param {number} width - Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      //https://mathworld.wolfram.com/Gaussian2DFunction.html
      return Gaussian2D$1.widthToFWHM(width);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/Gaussian2DFunction.html
     * @param {number} fwhm - Full Width at Half Maximum.
     * @returns {number} width
     */


    fwhmToWidth(fwhm = this.x.fwhm) {
      return Gaussian2D$1.fwhmToWidth(fwhm);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     * @param {string|Array<string>} axisLabel - label of axis, if it is undefined fwhm is set to both axis.
     */


    setFWHM(fwhm, axisLabel) {
      if (!axisLabel) axisLabel = axis$1;
      if (!Array.isArray(axisLabel)) axisLabel = [axisLabel];

      for (let i of axisLabel) {
        let axisName = i.toLowerCase();

        if (axisName !== 'y' && axisName !== 'x') {
          throw new Error('axis label should be x or y');
        }

        this[axisName].fwhm = fwhm;
      }
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a Gaussian2D shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} y - y value to calculate.
   * @param {number} fwhmX - full width half maximum in the x axis.
   * @param {number} fwhmY - full width half maximum in the y axis.
   * @returns {number} - the z value of bi-dimensional gaussian with the current parameters.
   */

  Gaussian2D$1.fct = function fct(x, y, xFWHM = 500, yFWHM = 500) {
    return Math.exp(GAUSSIAN_EXP_FACTOR$1 * (Math.pow(x / xFWHM, 2) + Math.pow(y / yFWHM, 2)));
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
   * //https://mathworld.wolfram.com/Gaussian2DFunction.html
   * @param {number} width - Width between the inflection points
   * @returns {number} fwhm
   */


  Gaussian2D$1.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_2LN2$1;
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/Gaussian2DFunction.html
   * @param {number} fwhm - Full Width at Half Maximum.
   * @returns {number} width
   */


  Gaussian2D$1.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_2LN2$1;
  };
  /**
   * Calculate the volume of a specific shape.
   * @param {number} xFWHM - Full width at half maximum for x axis.
   * @param {number} yFWHM - Full width at half maximum for y axis.
   * @param {object} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum z value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Gaussian2D$1.getVolume = function getVolume(xFWHM, yFWHM, options = {}) {
    let {
      height = 1
    } = options;
    return height * Math.PI * xFWHM * yFWHM / Math.LN2 / 4;
  };
  /**@TODO look for a better factor
   * Calculate the number of times FWHM allows to reach a specific volume coverage.
   * @param {number} [volume=0.9999]
   * @returns {number}
   */


  Gaussian2D$1.getFactor = function getFactor(volume = 0.9999) {
    return Math.sqrt(2) * erfinv$1(volume);
  };

  function getShapeGenerator$1(options) {
    let {
      kind = 'Gaussian',
      options: shapeOptions
    } = options;

    switch (kind.toLowerCase().replace(/[^a-z^0-9]/g, '')) {
      case 'gaussian':
        return new Gaussian$1(shapeOptions);

      case 'lorentzian':
        return new Lorentzian$1(shapeOptions);

      case 'pseudovoigt':
        return new PseudoVoigt$1(shapeOptions);

      case 'gaussian2d':
        return new Gaussian2D$1(shapeOptions);

      default:
        throw new Error(`Unknown kind: ${kind}`);
    }
  }

  /**
   * Apply Savitzky Golay algorithm
   * @param {array} [ys] Array of y values
   * @param {array|number} [xs] Array of X or deltaX
   * @param {object} [options={}]
   * @param {number} [options.windowSize=9]
   * @param {number} [options.derivative=0]
   * @param {number} [options.polynomial=3]
   * @return {array} Array containing the new ys (same length)
   */
  function SavitzkyGolay(ys, xs, options = {}) {
    let {
      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 (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');
    }

    let half = Math.floor(windowSize / 2);
    let np = ys.length;
    let ans = new Array(np);
    let weights = fullWeights(windowSize, polynomial, derivative);
    let hs = 0;
    let constantH = true;

    if (Array.isArray(xs)) {
      constantH = false;
    } else {
      hs = Math.pow(xs, derivative);
    } //For the borders


    for (let i = 0; i < half; i++) {
      let wg1 = weights[half - i - 1];
      let 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


    let 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 Math.pow(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++) {
      //console.log(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;
  }
  /**
   *
   * @param m  Number of points
   * @param n  Polynomial grade
   * @param s  Derivative
   */


  function fullWeights(m, n, s) {
    let weights = new Array(m);
    let np = Math.floor(m / 2);

    for (let t = -np; t <= np; t++) {
      weights[t + np] = new Array(m);

      for (let j = -np; j <= np; j++) {
        weights[t + np][j + np] = Weight(j, t, np, n, s);
      }
    }

    return weights;
  }
  /*function entropy(data,h,options){
      var trend = SavitzkyGolay(data,h,trendOptions);
      var copy = new Array(data.length);
      var sum = 0;
      var max = 0;
      for(var i=0;i<data.length;i++){
          copy[i] = data[i]-trend[i];
      }

      sum/=data.length;
      console.log(sum+" "+max);
      console.log(stat.array.standardDeviation(copy));
      console.log(Math.abs(stat.array.mean(copy))/stat.array.standardDeviation(copy));
      return sum;

  }



  function guessWindowSize(data, h){
      console.log("entropy "+entropy(data,h,trendOptions));
      return 5;
  }
  */

  /**
   * Global spectra deconvolution
   * @param {object} data - Object data with x and y arrays
   * @param {Array<number>} [data.x] - Independent variable
   * @param {Array<number>} [data.y] - Dependent variable
   * @param {object} [options={}] - Options object
   * @param {object} [options.shape={}] - Object that specified the kind of shape to calculate the FWHM instead of width between inflection points. see https://mljs.github.io/peak-shape-generator/#inflectionpointswidthtofwhm
   * @param {object} [options.shape.kind='gaussian']
   * @param {object} [options.shape.options={}]
   * @param {object} [options.sgOptions] - Options object for Savitzky-Golay filter. See https://github.com/mljs/savitzky-golay-generalized#options
   * @param {number} [options.sgOptions.windowSize = 9] - points to use in the approximations
   * @param {number} [options.sgOptions.polynomial = 3] - degree of the polynomial to use in the approximations
   * @param {number} [options.minMaxRatio = 0.00025] - Threshold to determine if a given peak should be considered as a noise
   * @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.
   * @param {number} [options.noiseLevel = 0] - Noise threshold in spectrum units
   * @param {boolean} [options.maxCriteria = true] - Peaks are local maximum(true) or minimum(false)
   * @param {boolean} [options.smoothY = true] - Select the peak intensities from a smoothed version of the independent variables
   * @param {boolean} [options.realTopDetection = false] - Use a quadratic optimizations with the peak and its 3 closest neighbors
   * to determine the true x,y values of the peak?
   * @param {number} [options.heightFactor = 0] - Factor to multiply the calculated height (usually 2)
   * @param {number} [options.derivativeThreshold = -1] - Filters based on the amplitude of the first derivative
   * @return {Array<object>}
   */

  function gsd(data, options = {}) {
    let {
      noiseLevel,
      sgOptions = {
        windowSize: 9,
        polynomial: 3
      },
      shape = {},
      smoothY = true,
      heightFactor = 0,
      broadRatio = 0.0,
      maxCriteria = true,
      minMaxRatio = 0.00025,
      derivativeThreshold = -1,
      realTopDetection = false
    } = options;
    let {
      y: yIn,
      x
    } = data;
    const y = yIn.slice();
    let equalSpaced = isEqualSpaced(x);

    if (noiseLevel === undefined) {
      noiseLevel = equalSpaced ? getNoiseLevel(y) : 0;
    }

    const yCorrection = {
      m: 1,
      b: noiseLevel
    };

    if (!maxCriteria) {
      yCorrection.m = -1;
      yCorrection.b *= -1;
    }

    for (let i = 0; i < y.length; i++) {
      y[i] = yCorrection.m * y[i] - yCorrection.b;
    }

    for (let i = 0; i < y.length; i++) {
      if (y[i] < 0) {
        y[i] = 0;
      }
    } // If the max difference between delta x is less than 5%, then,
    // we can assume it to be equally spaced variable


    let yData = y;
    let dY, ddY;
    const {
      windowSize,
      polynomial
    } = sgOptions;

    if (equalSpaced) {
      if (smoothY) {
        yData = SavitzkyGolay(y, x[1] - x[0], {
          windowSize,
          polynomial,
          derivative: 0
        });
      }

      dY = SavitzkyGolay(y, x[1] - x[0], {
        windowSize,
        polynomial,
        derivative: 1
      });
      ddY = SavitzkyGolay(y, x[1] - x[0], {
        windowSize,
        polynomial,
        derivative: 2
      });
    } else {
      if (smoothY) {
        yData = SavitzkyGolay(y, x, {
          windowSize,
          polynomial,
          derivative: 0
        });
      }

      dY = SavitzkyGolay(y, x, {
        windowSize,
        polynomial,
        derivative: 1
      });
      ddY = SavitzkyGolay(y, x, {
        windowSize,
        polynomial,
        derivative: 2
      });
    }

    const xData = x;
    const dX = x[1] - x[0];
    let maxDdy = 0;
    let maxY = 0;

    for (let i = 0; i < yData.length; i++) {
      if (Math.abs(ddY[i]) > maxDdy) {
        maxDdy = Math.abs(ddY[i]);
      }

      if (Math.abs(yData[i]) > maxY) {
        maxY = Math.abs(yData[i]);
      }
    }

    let lastMax = null;
    let lastMin = null;
    let minddY = [];
    let intervalL = [];
    let intervalR = [];
    let broadMask = []; // By the intermediate value theorem We cannot find 2 consecutive maximum or minimum

    for (let i = 1; i < yData.length - 1; ++i) {
      // filter based on derivativeThreshold
      // console.log('pasa', y[i], dY[i], ddY[i]);
      if (Math.abs(dY[i]) > derivativeThreshold) {
        // Minimum in first derivative
        if (dY[i] < dY[i - 1] && dY[i] <= dY[i + 1] || dY[i] <= dY[i - 1] && dY[i] < dY[i + 1]) {
          lastMin = {
            x: xData[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: xData[i],
            index: i
          };

          if (dX < 0 && lastMin !== null) {
            intervalL.push(lastMax);
            intervalR.push(lastMin);
          }
        }
      } // Minimum in second derivative


      if (ddY[i] < ddY[i - 1] && ddY[i] < ddY[i + 1]) {
        minddY.push(i);
        broadMask.push(Math.abs(ddY[i]) <= broadRatio * maxDdy);
      }
    }

    let widthProcessor = shape.kind ? getShapeGenerator$1(shape.kind, shape.options).widthToFWHM : x => x;
    let signals = [];
    let lastK = -1;
    let possible, frequency, distanceJ, minDistance, gettingCloser;

    for (let j = 0; j < minddY.length; ++j) {
      frequency = xData[minddY[j]];
      possible = -1;
      let k = lastK + 1;
      minDistance = Number.MAX_VALUE;
      distanceJ = 0;
      gettingCloser = true;

      while (possible === -1 && k < intervalL.length && gettingCloser) {
        distanceJ = Math.abs(frequency - (intervalL[k].x + intervalR[k].x) / 2); // Still getting closer?

        if (distanceJ < minDistance) {
          minDistance = distanceJ;
        } else {
          gettingCloser = false;
        }

        if (distanceJ < Math.abs(intervalL[k].x - intervalR[k].x) / 2) {
          possible = k;
          lastK = k;
        }

        ++k;
      }

      if (possible !== -1) {
        if (Math.abs(yData[minddY[j]]) > minMaxRatio * maxY) {
          let width = Math.abs(intervalR[possible].x - intervalL[possible].x);
          signals.push({
            index: minddY[j],
            x: frequency,
            y: (yData[minddY[j]] + yCorrection.b) / yCorrection.m,
            width: widthProcessor(width),
            soft: broadMask[j]
          });
          signals[signals.length - 1].left = intervalL[possible];
          signals[signals.length - 1].right = intervalR[possible];

          if (heightFactor) {
            let yLeft = yData[intervalL[possible].index];
            let yRight = yData[intervalR[possible].index];
            signals[signals.length - 1].height = heightFactor * (signals[signals.length - 1].y - (yLeft + yRight) / 2);
          }
        }
      }
    }

    if (realTopDetection) {
      determineRealTop(signals, xData, yData);
    } // Correct the values to fit the original spectra data


    for (let j = 0; j < signals.length; j++) {
      signals[j].base = noiseLevel;
    }

    signals.sort(function (a, b) {
      return a.x - b.x;
    });
    return signals;
  }

  const isEqualSpaced = x => {
    let tmp;
    let maxDx = 0;
    let minDx = Number.MAX_SAFE_INTEGER;

    for (let i = 0; i < x.length - 1; ++i) {
      tmp = Math.abs(x[i + 1] - x[i]);

      if (tmp < minDx) {
        minDx = tmp;
      }

      if (tmp > maxDx) {
        maxDx = tmp;
      }
    }

    return (maxDx - minDx) / maxDx < 0.05;
  };

  const getNoiseLevel = y => {
    let mean = 0;
    let stddev = 0;
    let length = y.length;

    for (let i = 0; i < length; ++i) {
      mean += y[i];
    }

    mean /= length;
    let averageDeviations = new Array(length);

    for (let i = 0; i < length; ++i) {
      averageDeviations[i] = Math.abs(y[i] - mean);
    }

    averageDeviations.sort((a, b) => a - b);

    if (length % 2 === 1) {
      stddev = averageDeviations[(length - 1) / 2] / 0.6745;
    } else {
      stddev = 0.5 * (averageDeviations[length / 2] + averageDeviations[length / 2 - 1]) / 0.6745;
    }

    return stddev;
  };

  const determineRealTop = (peakList, x, y) => {
    let alpha, beta, gamma, p, currentPoint;

    for (let j = 0; j < peakList.length; j++) {
      currentPoint = peakList[j].index; // peakList[j][2];
      // The detected peak could be moved 1 or 2 units to left or right.

      if (y[currentPoint - 1] >= y[currentPoint - 2] && y[currentPoint - 1] >= y[currentPoint]) {
        currentPoint--;
      } else {
        if (y[currentPoint + 1] >= y[currentPoint] && y[currentPoint + 1] >= y[currentPoint + 2]) {
          currentPoint++;
        } else {
          if (y[currentPoint - 2] >= y[currentPoint - 3] && y[currentPoint - 2] >= y[currentPoint - 1]) {
            currentPoint -= 2;
          } else {
            if (y[currentPoint + 2] >= y[currentPoint + 1] && y[currentPoint + 2] >= y[currentPoint + 3]) {
              currentPoint += 2;
            }
          }
        }
      } // interpolation to a sin() function


      if (y[currentPoint - 1] > 0 && y[currentPoint + 1] > 0 && y[currentPoint] >= y[currentPoint - 1] && y[currentPoint] >= y[currentPoint + 1] && (y[currentPoint] !== y[currentPoint - 1] || y[currentPoint] !== y[currentPoint + 1])) {
        alpha = 20 * Math.log10(y[currentPoint - 1]);
        beta = 20 * Math.log10(y[currentPoint]);
        gamma = 20 * Math.log10(y[currentPoint + 1]);
        p = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma); // console.log(alpha, beta, gamma, `p: ${p}`);
        // console.log(x[currentPoint]+" "+tmp+" "+currentPoint);

        peakList[j].x = x[currentPoint] + (x[currentPoint] - x[currentPoint - 1]) * p;
        peakList[j].y = y[currentPoint] - 0.25 * (y[currentPoint - 1] - y[currentPoint + 1]) * p;
      }
    }
  };

  const toString$5 = Object.prototype.toString;
  function isAnyArray$3(object) {
    return toString$5.call(object).endsWith('Array]');
  }

  function max$5(input) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    if (!isAnyArray$3(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;
  }

  const toString$4 = Object.prototype.toString;
  function isAnyArray$2(object) {
    return toString$4.call(object).endsWith('Array]');
  }

  const toString$3 = Object.prototype.toString;
  function isAnyArray$1(object) {
    return toString$3.call(object).endsWith('Array]');
  }

  function min$6(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(input) {
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    if (!isAnyArray$2(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$2(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$6(input);
    var currentMax = max$5(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;
  }

  const indent = ' '.repeat(2);
  const indentData = ' '.repeat(4);
  function inspectMatrix() {
    return inspectMatrixWithOptions(this);
  }
  function inspectMatrixWithOptions(matrix, options = {}) {
    const {
      maxRows = 15,
      maxColumns = 10,
      maxNumSize = 8
    } = options;
    return `${matrix.constructor.name} {
${indent}[
${indentData}${inspectData(matrix, maxRows, maxColumns, maxNumSize)}
${indent}]
${indent}rows: ${matrix.rows}
${indent}columns: ${matrix.columns}
}`;
  }

  function inspectData(matrix, maxRows, maxColumns, maxNumSize) {
    const {
      rows,
      columns
    } = matrix;
    const maxI = Math.min(rows, maxRows);
    const maxJ = Math.min(columns, maxColumns);
    const result = [];

    for (let i = 0; i < maxI; i++) {
      let line = [];

      for (let j = 0; j < maxJ; j++) {
        line.push(formatNumber(matrix.get(i, j), maxNumSize));
      }

      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) {
    const numStr = String(num);

    if (numStr.length <= maxNumSize) {
      return numStr.padEnd(maxNumSize, ' ');
    }

    const precise = num.toPrecision(maxNumSize - 2);

    if (precise.length <= maxNumSize) {
      return precise;
    }

    const exponential = num.toExponential(maxNumSize - 2);
    const eIndex = exponential.indexOf('e');
    const e = exponential.slice(eIndex);
    return exponential.slice(0, maxNumSize - e.length) + e;
  }

  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, Math.pow(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, Math.pow(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 checkIndices(matrix, rowIndices, columnIndices) {
    return {
      row: checkRowIndices(matrix, rowIndices),
      column: checkColumnIndices(matrix, columnIndices)
    };
  }
  function checkRowIndices(matrix, rowIndices) {
    if (typeof rowIndices !== 'object') {
      throw new TypeError('unexpected type for row indices');
    }

    let rowOut = rowIndices.some(r => {
      return r < 0 || r >= matrix.rows;
    });

    if (rowOut) {
      throw new RangeError('row indices are out of range');
    }

    if (!Array.isArray(rowIndices)) rowIndices = Array.from(rowIndices);
    return rowIndices;
  }
  function checkColumnIndices(matrix, columnIndices) {
    if (typeof columnIndices !== 'object') {
      throw new TypeError('unexpected type for column indices');
    }

    let columnOut = columnIndices.some(c => {
      return c < 0 || c >= matrix.columns;
    });

    if (columnOut) {
      throw new RangeError('column indices are out of range');
    }

    if (!Array.isArray(columnIndices)) columnIndices = Array.from(columnIndices);
    return columnIndices;
  }
  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 += Math.pow(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 += Math.pow(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 += Math.pow(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;
    }

    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() {
      if (this.isEmpty()) {
        return NaN;
      }

      let v = this.get(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);
          }
        }
      }

      return v;
    }

    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() {
      if (this.isEmpty()) {
        return NaN;
      }

      let v = this.get(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);
          }
        }
      }

      return v;
    }

    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') {
      let result = 0;

      if (type === 'max') {
        return this.max();
      } else if (type === 'frobenius') {
        for (let i = 0; i < this.rows; i++) {
          for (let j = 0; j < this.columns; j++) {
            result = result + this.get(i, j) * this.get(i, j);
          }
        }

        return Math.sqrt(result);
      } else {
        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;
    }

    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 resultat = AbstractMatrix.zeros(2 * c11.rows, 2 * c11.columns);
        resultat = resultat.setSubMatrix(c11, 0, 0);
        resultat = resultat.setSubMatrix(c12, c11.rows, 0);
        resultat = resultat.setSubMatrix(c21, 0, c11.columns);
        resultat = resultat.setSubMatrix(c22, c11.rows, c11.columns);
        return resultat.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(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(column, {
            min: min,
            max: 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) {
      let indices = checkIndices(this, rowIndices, columnIndices);
      let newMatrix = new Matrix$1(rowIndices.length, columnIndices.length);

      for (let i = 0; i < indices.row.length; i++) {
        let rowIndex = indices.row[i];

        for (let j = 0; j < indices.column.length; j++) {
          let columnIndex = indices.column[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() {
      let newMatrix = new Matrix$1(this.rows, this.columns);

      for (let row = 0; row < this.rows; row++) {
        for (let column = 0; column < this.columns; column++) {
          newMatrix.set(row, column, this.get(row, column));
        }
      }

      return newMatrix;
    }

    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 (!Array.isArray(mean)) {
              throw new TypeError('mean must be an array');
            }

            return varianceByRow(this, unbiased, mean);
          }

        case 'column':
          {
            if (!Array.isArray(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 (!Array.isArray(center)) {
              throw new TypeError('center must be an array');
            }

            centerByRow(this, center);
            return this;
          }

        case 'column':
          {
            if (!Array.isArray(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 (!Array.isArray(scale)) {
              throw new TypeError('scale must be an array');
            }

            scaleByRow(this, scale);
            return this;
          }

        case 'column':
          {
            if (scale === undefined) {
              scale = getScaleByColumn(this);
            } else if (!Array.isArray(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);
    }

  }
  AbstractMatrix.prototype.klass = 'Matrix';

  if (typeof Symbol !== 'undefined') {
    AbstractMatrix.prototype[Symbol.for('nodejs.util.inspect.custom')] = inspectMatrix;
  }

  function compareNumbers(a, b) {
    return a - b;
  } // 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;
  class Matrix$1 extends AbstractMatrix {
    constructor(nRows, nColumns) {
      super();

      if (Matrix$1.isMatrix(nRows)) {
        // eslint-disable-next-line no-constructor-return
        return nRows.clone();
      } else if (Number.isInteger(nRows) && nRows >= 0) {
        // Create an empty matrix
        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');
        }
      } else if (Array.isArray(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');
          }

          this.data.push(Float64Array.from(arrayData[i]));
        }
      } else {
        throw new TypeError('First argument must be a positive number or an array');
      }

      this.rows = nRows;
      this.columns = nColumns;
    }

    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);

  /**
   * Aligns the data based on a range and means of peaks in this range
   * Based on a range we will make a peak picking using global spectra deconvolution
   * The selected nbPeaks will then be taken into account to calculate an average X value.
   * The difference between the targetX and the averageX value will be returned
   * @param {DataXY} [data] array of points {x,y}
   * @param {Object} [range={}]
   * @param {number} [range.from] - Beginning of the range where the interest signal is localed
   * @param {number} [range.to] - End of the range where the interest signal is localed
   * @param {Object} [options={}]
   * @param {number} [options.nbPeaks=1] Number of peaks to consider to calculate mean (sorted by height)
   * @param {number} [options.targetX=0] Expected value for the mean of the peaks position
   * @param {number} [options.gsd={}] GSD options. You may check options here: http://mljs.github.io/global-spectral-deconvolution/#gsd
   * @param {number} [options.gsd.minMaxRatio=0.2] - GSD Threshold to determine if a given peak should be considered as a noise.
   * @returns {number} difference between targetX and currentX
   */

  function xyXShift(data, range = {}, options = {}) {
    const {
      targetX = 0,
      nbPeaks = 1,
      gsd: gsdOptions = {
        minMaxRatio: 0.1,
        realTopDetection: true,
        smoothY: true,
        sgOptions: {
          windowSize: 7,
          polynomial: 3
        }
      }
    } = options;
    let {
      from,
      to
    } = range;
    if (from === undefined || to === undefined) return 0;
    const fromIndex = xFindClosestIndex$1(data.x, from);
    const toIndex = xFindClosestIndex$1(data.x, to);
    const sliceddata = {
      x: data.x.slice(fromIndex, toIndex),
      y: data.y.slice(fromIndex, toIndex)
    };
    let peaks = gsd(sliceddata, gsdOptions).sort((a, b) => b.y - a.y).slice(0, nbPeaks);
    if (peaks.length === 0) return 0;
    const middle = mean(peaks.map(peak => peak.x));
    return targetX - middle;
  }

  /**
   *This function performs a quick sort of the x array while transforming the y array to preserve the coordinates.
   * @param {DataXY} [data] Object that contains property x (Array) and y (Array)
   */
  function xySortX(data) {
    const {
      x,
      y
    } = data;
    let xyObject = x.map((val, index) => ({
      x: val,
      y: y[index]
    })).sort((a, b) => a.x - b.x);
    let response = {
      x: [],
      y: []
    };

    for (let i = 0; i < x.length; i++) {
      response.x.push(xyObject[i].x);
      response.y.push(xyObject[i].y);
    }

    return response;
  }

  /**
   * Ensure x values are unique
   * @param {DataXY} [data] Object that contains property x (Array) and y (Array)
   * @param {Object} [options={}] Object containing a property algorithm (can be 'sum' or 'average', the latter being the default value), and a property isSorted (boolean indicating if the x-array is sorted).
   * @param {string} [options.algorithm='average'] either 'average' or 'sum'
   * @param {boolean} [options.isSorted=true] if false the DataXY has to be sorted first
   * @returns {DataXY}
   */

  function xyUniqueX(data, options = {}) {
    xyCheck(data);
    const {
      algorithm = 'average',
      isSorted = true
    } = options;

    if (!isSorted) {
      data = xySortX(data);
    }

    switch (algorithm) {
      case 'average':
        return average(data);

      case 'sum':
        return sum$1(data);

      default:
        throw new Error(`xyUniqueX: unknown algorithm: ${algorithm}`);
    }
  }

  function average(data) {
    let x = [];
    let y = [];
    let cumulativeY = data.y[0];
    let divider = 1;

    for (let i = 1; i < data.x.length; i++) {
      if (!(data.x[i] === data.x[i - 1])) {
        x.push(data.x[i - 1]);
        y.push(cumulativeY / divider);
        cumulativeY = 0;
        divider = 0;
      }

      cumulativeY += data.y[i];
      divider++;
    }

    x.push(data.x[data.x.length - 1]);
    y.push(cumulativeY / divider);
    return {
      x,
      y
    };
  }

  function sum$1(data) {
    let x = [];
    let y = [];
    let cumulativeY = data.y[0];

    for (let i = 1; i < data.x.length; i++) {
      if (!(data.x[i] === data.x[i - 1])) {
        x.push(data.x[i - 1]);
        y.push(cumulativeY);
        cumulativeY = 0;
      }

      cumulativeY += data.y[i];
    }

    x.push(data.x[data.x.length - 1]);
    y.push(cumulativeY);
    return {
      x,
      y
    };
  }

  /**
   * Throw an error in no an object of x,y arrays
   * @param {ArrayPoints} [points=[]]
   */
  function xyObjectCheck(points = []) {
    if (!Array.isArray(points)) {
      throw new Error('ArrayPoints must be an array of {x,y} object');
    }

    if (points.length > 0 && (points[0].x === undefined || points[0].y === undefined)) {
      throw new Error('ArrayPoints must be an array of {x,y} object');
    }
  }

  /**
   * Finds the max x value and return a {x,y,index} point
   * @param {DataXY} [points=[]] - Object that contains property x (an ordered increasing array) and y (an array)
   * @return {object}
   */

  function xyObjectMaxXPoint(points = []) {
    xyObjectCheck(points);
    if (points.length < 1) return {};
    let current = {
      x: points[0].x,
      y: points[0].y,
      index: 0
    };

    for (let i = 1; i < points.length; i++) {
      if (points[i].x > current.x) {
        current = {
          x: points[i].x,
          y: points[i].y,
          index: i
        };
      }
    }

    return current;
  }

  /**
   * Finds the min x value and return a {x,y,index} point
   * @param {DataXY} [points=[]] - Object that contains property x (an ordered increasing array) and y (an array)
   * @return {object}
   */

  function xyObjectMinXPoint(points = []) {
    xyObjectCheck(points);
    if (points.length < 1) return {};
    let current = {
      x: points[0].x,
      y: points[0].y,
      index: 0
    };

    for (let i = 1; i < points.length; i++) {
      if (points[i].x < current.x) {
        current = {
          x: points[i].x,
          y: points[i].y,
          index: i
        };
      }
    }

    return current;
  }

  /**
   * Filter the array by taking the higher points (max y value) and only
   * keep one per slot.
   * There are 2 different slots, the smallest one will have the
   * new property `close` to true
   * @param {array} points - array of all the points
   * @param {object} [options={}]
   * @param {number} [options.from] - min X value of the window to consider
   * @param {number} [options.to] - max X value of the window to consider
   * @param {number} [options.limit=20] - max number of points
   * @param {number} [options.threshold=0.01] - minimal intensity compare to more intense point
   * @param {number} [options.numberSlots=10] - define the number of slots and indirectly the slot width
   * @param {number} [options.numberCloseSlots=50]
   * @returns {array} - copy of points with 'close' property
   */

  function xyObjectBestPoints(points, options = {}) {
    const {
      from = xyObjectMinXPoint(points).x,
      to = xyObjectMaxXPoint(points).x,
      limit = 20,
      threshold = 0.01,
      numberCloseSlots = 50,
      numberSlots = 10
    } = options;
    let slot = (to - from) / numberSlots;
    let closeSlot = (to - from) / numberCloseSlots;
    let selected = points.filter(point => point.x >= from && point.x <= to).map(point => {
      return {
        point,
        monoisotopic: false
      };
    });
    selected = selected.sort((a, b) => {
      if (a.monoisotopic && !b.monoisotopic) return -1;
      if (b.monoisotopic && !a.monoisotopic) return 1;
      return b.point.y - a.point.y;
    });
    let toReturn = [];
    if (selected.length === 0) return [];
    let minY = selected[0].point.y * threshold;

    peakLoop: for (let item of selected) {
      if (item.point.y < minY) {
        if (item.monoisotopic) {
          continue;
        } else {
          break;
        }
      }

      let close = false;

      for (let existing of toReturn) {
        if (Math.abs(existing.x - item.point.x) < closeSlot) {
          continue peakLoop;
        }

        if (Math.abs(existing.x - item.point.x) < slot) {
          close = true;
        }
      }

      let newPeak = JSON.parse(JSON.stringify(item.point));
      newPeak.close = close;
      toReturn.push(newPeak);
      if (toReturn.length === limit) break;
    }

    return toReturn.sort((a, b) => a.x - b.x);
  }

  /**
   *
   * @param {ArrayPoints} [points] array of growing points {x,y}
   * @param {object} [options={}]
   * @param {object} [xError=Number.EPSILON] limit to join the data
   */
  function xyObjectJoinX(points, options = {}) {
    const {
      xError = Number.EPSILON
    } = options; // when we join we will use the center of mass

    let result = [];
    let current = {
      x: Number.MIN_SAFE_INTEGER,
      y: 0
    };

    for (let point of points) {
      if (point.x - current.x <= xError) {
        // weighted sum
        current.x = point.y / (current.y + point.y) * (point.x - current.x) + current.x;
        current.y += point.y;
      } else {
        current = {
          x: point.x,
          y: point.y
        };
        result.push(current);
      }
    }

    return result;
  }

  /**
   * Finds the max y value and return a {x,y,index} point
   * @param {DataXY} [points=[]] - Object that contains property x (an ordered increasing array) and y (an array)
   * @return {object}
   */

  function xyObjectMaxYPoint(points = []) {
    xyObjectCheck(points);
    if (points.length < 1) return {};
    let current = {
      x: points[0].x,
      y: points[0].y,
      index: 0
    };

    for (let i = 1; i < points.length; i++) {
      if (points[i].y > current.y) {
        current = {
          x: points[i].x,
          y: points[i].y,
          index: i
        };
      }
    }

    return current;
  }

  /**
   * Finds the min y value and return a {x,y,index} point
   * @param {DataXY} [points=[]] - Object that contains property x (an ordered increasing array) and y (an array)
   * @return {object}
   */

  function xyObjectMinYPoint(points = []) {
    xyObjectCheck(points);
    if (points.length < 1) return {};
    let current = {
      x: points[0].x,
      y: points[0].y,
      index: 0
    };

    for (let i = 1; i < points.length; i++) {
      if (points[i].y < current.y) {
        current = {
          x: points[i].x,
          y: points[i].y,
          index: i
        };
      }
    }

    return current;
  }

  /**
   *
   * @param {ArrayPoints} [points] array of growing points {x,y}
   * @param {object} [options={}]
   * @param {object} [slotWidth=1] limit to join the data
   */
  function xyObjectSlotX(points, options = {}) {
    const {
      slotWidth = 1
    } = options;
    const halfSlot = slotWidth / 2; // when we join we will use the center of mass

    let result = [];
    let current = {
      x: Number.MIN_VALUE,
      y: 0
    };

    for (let point of points) {
      let slot = point.x - (point.x + halfSlot) % slotWidth + halfSlot;

      if (Math.abs(current.x - slot) > Number.EPSILON) {
        current = {
          x: slot,
          y: 0
        };
        result.push(current);
      }

      current.y += point.y;
    }

    return result;
  }

  /**
   * Sorts an array of points
   * @param {ArrayPoints} [points] array of points {x,y}
   */
  function xyObjectSortX(points) {
    return points.sort((a, b) => a.x - b.x);
  }

  /**
   *
   * @param {ArrayPoints} [points] array of points {x,y}
   */
  function xyObjectToXY(points) {
    return {
      x: points.map(entry => entry.x),
      y: points.map(entry => entry.y)
    };
  }

  function zoneToX(zone, size) {
    const {
      from,
      to
    } = zone;
    let array = new Float64Array(size);
    let step = (to - from) / (size - 1);

    for (let i = 0; i < size; i++) {
      array[i] = from + step * i;
    }

    return array;
  }

  /**
   * Performs a Probabilistic quotient normalization over the dataset to account dilution based in median spectrum.
   * Dieterle, F., Ross, A., Schlotterbeck, G., & Senn, H. (2006). Probabilistic quotient normalization as robust method to account for dilution of complex biological mixtures. Application in 1H NMR metabonomics. Analytical chemistry, 78(13), 4281-4290.
   * DOI: 10.1021/ac051632c
   * @param {Matrix} [matrix] - matrix [rows][cols].
   * @param {Object} [options={}]
   * @param {number} [options.max=100] - Normalization integral constant.
   * @return {Object} { data, averageQuotients }.
   * data: Normalized dataset.
   * averageQuotients: The quotients of all variables of interest.
   */

  function probabilisticQuotientNormalization(matrix, options = {}) {
    let {
      max = 100
    } = options;
    matrix = new Matrix$1(matrix);

    for (let i = 0; i < matrix.rows; i++) {
      let row = matrix.getRowVector(i).div(matrix.getRowVector(i).norm() / max);
      matrix.setRow(i, row);
    }

    let normalizationFactor = matrix.norm() / max;
    matrix.div(normalizationFactor);
    let referenceSpectrum = [];

    for (let i = 0; i < matrix.columns; i++) {
      let currentVariable = [];

      for (let j = 0; j < matrix.rows; j++) {
        currentVariable.push(matrix.get(j, i));
      }

      referenceSpectrum.push(mean(currentVariable));
    }

    let averageQuotients = [];

    for (let i = 0; i < matrix.rows; i++) {
      let quotients = [];

      for (let j = 0; j < matrix.columns; j++) {
        let quotient = matrix.get(i, j) / referenceSpectrum[j];
        quotients.push(quotient);
      }

      averageQuotients.push(mean(quotients));
    }

    for (let i = 0; i < matrix.rows; i++) {
      matrix.mulRow(i, averageQuotients[i]);
    }

    return {
      data: matrix,
      averageQuotients: averageQuotients
    };
  }

  /**
   * @typedef {Object} DataXY
   * @property {Array<Number>} x Array of x values
   * @property {Array<Number>} y Array of y values
   */

  var src$g = /*#__PURE__*/Object.freeze({
    __proto__: null,
    xAbsolute: xAbsolute,
    xAbsoluteMedian: xAbsoluteMedian,
    xAdd: xAdd,
    xAutoCorrelation: xAutoCorrelation,
    xBoxPlot: xBoxPlot,
    xCorrelation: xCorrelation,
    xCrossCorrelation: xCrossCorrelation,
    xDivide: xDivide,
    xFindClosestIndex: xFindClosestIndex$1,
    xGetFromToIndex: xGetFromToIndex,
    xGetTargetIndex: xGetTargetIndex,
    xIsMonotone: xIsMonotone,
    xMultiply: xMultiply,
    xNoiseSanPlot: xNoiseSanPlot,
    xNorm: xNorm,
    xPadding: xPadding,
    xRotate: xRotate,
    xRolling: xRolling,
    xRollingAverage: xRollingAverage,
    xRollingMedian: xRollingMedian,
    xSubtract: xSubtract,
    xMinIndex: xMinIndex,
    xMaxIndex: xMaxIndex,
    reimAbsolute: reimAbsolute,
    reimAutoPhaseCorrection: reimAutoPhaseCorrection,
    reimPhaseCorrection: reimPhaseCorrection,
    reimFFT: reimFFT,
    xreimZeroFilling: xreimZeroFilling,
    xreimSortX: xreimSortX,
    xyAlign: xyAlign,
    xyCheck: xyCheck,
    xyExtract: xyExtract,
    xyGetNMaxY: xyGetNMaxY,
    xyGrowingX: xyGrowingX,
    xyIntegral: xyIntegral,
    xyIntegration: xyIntegration,
    xyMaxClosestYPoint: xyMaxClosestYPoint,
    xyMaxY: xyMaxY,
    xyMaxYPoint: xyMaxYPoint,
    xyMaximaY: xyMaximaY,
    xyMinClosestYPoint: xyMinClosestYPoint,
    xyMinYPoint: xyMinYPoint,
    xyMinimaY: xyMinimaY,
    xyPeakInfo: xyPeakInfo,
    xyRealMaxYPoint: xyRealMaxYPoint,
    xyRealMinYPoint: xyRealMinYPoint,
    xyReduce: xyReduce,
    xyRolling: xyRolling,
    xyToXYObject: xyToXYObject,
    xyToXYArray: xyToXYArray,
    xyXShift: xyXShift,
    xyUniqueX: xyUniqueX,
    xySortX: xySortX,
    xyObjectBestPoints: xyObjectBestPoints,
    xyObjectJoinX: xyObjectJoinX,
    xyObjectMaxXPoint: xyObjectMaxXPoint,
    xyObjectMinXPoint: xyObjectMinXPoint,
    xyObjectMaxYPoint: xyObjectMaxYPoint,
    xyObjectMinYPoint: xyObjectMinYPoint,
    xyObjectSlotX: xyObjectSlotX,
    xyObjectSortX: xyObjectSortX,
    xyObjectToXY: xyObjectToXY,
    zoneToX: zoneToX,
    zonesNormalize: zonesNormalize,
    probabilisticQuotientNormalization: probabilisticQuotientNormalization
  });

  var require$$0$2 = /*@__PURE__*/getAugmentedNamespace(src$g);

  const xFindClosestIndex = require$$0$2.xFindClosestIndex;
  /**
   * @param {object}         [entry={}}]
   * @param {object}         [options={}}]
   * @param {object}         [options.ionization={ mf: '', em: 0, charge: 0 }] - ionization method
   * @param {boolean}        [options.forceIonization=false] - If true ignore existing ionizations
   * @param {number}         [options.precision=1000] - The precision on the experimental mass
   * @param {number}         [options.targetMass] - Target mass, allows to calculate error and filter results
   * @param {Array<number>}  [options.targetMasses] - Target masses: SORTED array of numbers
   * @param {Array<number>}  [options.targetIntensities] - Target intensities: SORTED array of numbers
   * @param {number}         [options.minEM=0] - Minimal monoisotopic mass
   * @param {number}         [options.maxEM=+Infinity] - Maximal monoisotopic mass
   * @param {number}         [options.minMSEM=0] - Minimal monoisotopic mass observed by mass
   * @param {number}         [options.maxMSEM=+Infinity] - Maximal monoisotopic mass observed by mass
   * @param {number}         [options.minCharge=-Infinity] - Minimal charge
   * @param {number}         [options.maxCharge=+Infinity] - Maximal charge
   * @param {object}         [options.unsaturation={}}]
   * @param {number}         [options.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number}         [options.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number}         [options.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number}         [options.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {object}         [options.atoms] - object of atom:{min, max}
   * @param {Function}       [options.callback] - a function that contains information about the current MF
   * @return {boolean}
   */

  /**
   * We always recalculate msem
   */

  var msemMatcher = function msemMatcher(entry, options = {}) {
    const {
      ionization = {
        mf: '',
        em: 0,
        charge: 0
      },
      forceIonization = false,
      precision = 1000,
      minCharge = Number.MIN_SAFE_INTEGER,
      maxCharge = Number.MAX_SAFE_INTEGER,
      unsaturation = {},
      targetMass,
      // if present we will calculate the errors
      targetMasses,
      // if present we will calculate the smallest error
      targetIntensities,
      // if present it will be added in the report
      minEM = -Infinity,
      maxEM = +Infinity,
      minMSEM = -Infinity,
      maxMSEM = +Infinity,
      atoms,
      callback
    } = options;
    let msInfo = getMsInfo(entry, {
      ionization,
      forceIonization,
      targetMass
    });
    let ms = msInfo.ms;

    if (entry.em !== undefined) {
      if (entry.em < minEM || entry.em > maxEM) return false;
    }

    if (ms.em !== undefined) {
      if (ms.em < minMSEM || ms.em > maxMSEM) return false;
    }

    if (targetMass && Math.abs(ms.ppm) > precision) return false;

    if (entry.charge !== undefined) {
      if (ms.charge < minCharge || ms.charge > maxCharge) return false;
    }

    if (unsaturation !== undefined && entry.unsaturation !== undefined) {
      if (!unsaturationMatcher(entry, unsaturation)) {
        return false;
      }
    }

    if (entry.atoms !== undefined && atoms) {
      // all the atoms of the entry must fit in the range
      for (let atom of Object.keys(entry.atoms)) {
        if (!atoms[atom]) return false;
        if (entry.atoms[atom] < atoms[atom].min) return false;
        if (entry.atoms[atom] > atoms[atom].max) return false;
      }
    }

    if (targetMasses && targetMasses.length > 0) {
      let index = xFindClosestIndex(targetMasses, ms.em);
      let closestMass = targetMasses[index];
      msInfo = getMsInfo(entry, {
        ionization,
        forceIonization,
        targetMass: closestMass
      });
      msInfo.ms.target = {
        mass: closestMass
      };

      if (targetIntensities) {
        msInfo.ms.target.intensity = targetIntensities[index];
      } // need to find the closest targetMasses


      if (Math.abs(msInfo.ms.ppm) > precision) return false;
    }

    if (callback) {
      if (!callback(entry)) return false;
    }

    return msInfo;
  };

  var src$f = {
    general: generalMatcher,
    msem: msemMatcher
  };

  function processRange(string, comment, options = {}) {
    const {
      limit
    } = options;
    let results = [];
    let parts = string.split(/(-?[0-9]+--?[0-9]+)/).filter(v => v); // remove empty parts

    let position = -1;
    let mfs = [];

    for (let i = 0; i < parts.length; i++) {
      let part = parts[i];

      if (!~part.search(/-?[0-9]--?[0-9]/)) {
        position++;
        mfs[position] = {
          mf: part,
          min: 1,
          max: 1
        };
      } else {
        let min = part.replace(/^(-?[0-9]*)-(-?[0-9]*)/, '$1') >> 0;
        let max = part.replace(/^(-?[0-9]*)-(-?[0-9]*)/, '$2') >> 0;
        mfs[position].min = Math.min(min, max);
        mfs[position].max = Math.max(min, max);
      }
    }

    let currents = new Array(mfs.length);

    for (let i = 0; i < currents.length; i++) {
      currents[i] = mfs[i].min;
    }

    position = 0;

    while (position < currents.length) {
      if (currents[position] < mfs[position].max) {
        results.push(getMF(mfs, currents, comment));
        currents[position]++;

        for (let i = 0; i < position; i++) {
          currents[i] = mfs[i].min;
        }

        position = 0;
      } else {
        position++;
      }

      if (results.length > limit) {
        throw Error(`processRange generates to many fragments (over ${limit})`);
      }
    }

    results.push(getMF(mfs, currents, comment));
    return results;
  }

  function getMF(mfs, currents, comment) {
    let mf = '';

    for (let i = 0; i < mfs.length; i++) {
      if (currents[i] === 0) {
        // TODO we need to remove from currents[i] till we reach another part of the MF
        mf += removeMFLastPart(mfs[i].mf);
      } else {
        mf += mfs[i].mf;

        if (currents[i] !== 1) {
          mf += currents[i];
        }
      }
    }

    if (comment) mf += `$${comment}`;
    return mf;
  }
  /*
     Allows to remove the last part of a MF. Useful when you have something with '0' times.
     C10H -> C10
     C10((Me)N) -> C10
     C10Ala -> C10
     C10Ala((Me)N) -> C10Ala
     */


  function removeMFLastPart(mf) {
    let parenthesis = 0;
    let start = true;

    for (let i = mf.length - 1; i >= 0; i--) {
      let ascii = mf.charCodeAt(i);

      if (ascii > 96 && ascii < 123) {
        // lowercase
        if (!start && !parenthesis) {
          return mf.substr(0, i + 1);
        }
      } else if (ascii > 64 && ascii < 91) {
        // uppercase
        if (!start && !parenthesis) {
          return mf.substr(0, i + 1);
        }

        start = false;
      } else if (ascii === 40) {
        // (
        parenthesis--;
        if (!parenthesis) return mf.substr(0, i);
      } else if (ascii === 41) {
        // )
        parenthesis++;
      } else {
        start = false;
        if (!parenthesis) return mf.substr(0, i + 1);
      }
    }

    return '';
  }

  var processRange_1 = processRange;

  var preprocessIonizations = function preprocessIonizations(ionizationsString = '') {
    if (Array.isArray(ionizationsString)) return ionizationsString;
    let ionizations = ionizationsString.split(/ *[.,;\t\r\n]+ */); // it is allowed to have ranges in Ionizations. We need to explode them.

    let results = [];

    for (let ionization of ionizations) {
      let parts = processRange_1(ionization);

      for (let part of parts) {
        let info = new MF_1(part).getInfo();
        results.push({
          mf: part,
          em: info.monoisotopicMass,
          charge: info.charge
        });
      }
    }

    return results;
  };

  /**
   * Modify object a to join it with b and make the sum of each of the keys
   * @param {*} a
   * @param {*} source1
   *
   * @return {object}
   */

  function sum(target) {
    for (var i = 1; i < arguments.length; i++) {
      let toSum = arguments[i];

      for (var key of Object.keys(toSum)) {
        if (target[key]) {
          target[key] += toSum[key];
        } else {
          target[key] = toSum[key];
        }
      }
    }

    return target;
  }

  var lib$3 = sum;

  const {
    ELECTRON_MASS: ELECTRON_MASS$3
  } = constants;
  const MF$2 = src$h.MF;
  const matcher$2 = src$f.msem;
  /**
   * Generate all the possible combinations of molecular formula and calculate
   * for each of them the monoisotopic mass and observed moniisotopic mass (m/z)
   * In the molecular formula there may be a comment after the '$' symbol
   *
   * @param keys
   * @param {object}        [options={}]
   * @param {number}        [options.limit=10000000] - Maximum number of results
   * @param {boolean}       [options.estimate=false] - estimate the number of MF without filters
   * @param {boolean}       [canonizeMF=true] - Canonize molecular formula
   * @param {boolean}       [uniqueMFs=true] - Force canonization and make MF unique
   * @param {string}        [ionizations=''] - Comma separated list of ionizations (to charge the molecule)
   * @param {number}        [options.filter.minMass=0] - Minimal monoisotopic mass
   * @param {number}        [options.filter.maxMass=+Infinity] - Maximal monoisotopic mass
   * @param {number}        [options.filter.minEM=0] - Minimal neutral monoisotopic mass
   * @param {number}        [options.filter.maxEM=+Infinity] - Maximal neutral monoisotopic mass
   * @param {number}        [options.filter.precision=1000] - The precision on the experimental mass
   * @param {number}        [options.filter.targetMass] - Target mass, allows to calculate error and filter results
   * @param {Array<number>} [options.filter.targetMasses] - Target masses: SORTED array of numbers
   * @param {number}        [options.filter.precision=1000] - Precision
   * @param {number}        [options.filter.minCharge=-Infinity] - Minimal charge
   * @param {number}        [options.filter.maxCharge=+Infinity] - Maximal charge
   * @param {object}        [options.filter.unsaturation={}}]
   * @param {number}        [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number}        [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number}        [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number}        [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {object}        [options.filter.atoms] - object of atom:{min, max}
   * @param {function}      [options.filter.callback] - a function to filter the MF
   * @param {string}        [options.filterFct]
   * @param {object}        [options.links]
   * @param {boolean}       [options.links.filter] We filter all the MF that do not match the '*X'
   * @returns {Array}
   */

  var src$e = function generateMFs(keys, options = {}) {
    options = { ...options
    };
    let {
      limit = 100000,
      uniqueMFs = true,
      estimate = false
    } = options;
    options.filterFctVariables = {};

    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];

      if (typeof key === 'object' && key.name) {
        options.filterFctVariables[key.name] = i;
        keys[i] = key.value;
      }
    }

    if (options.filterFct) {
      // we create a real javascript function
      let variables = Object.keys(options.filterFctVariables);
      variables.push('mm', 'mz', 'charge', 'unsaturation', 'atoms'); // eslint-disable-next-line no-new-func

      options.filterFct = new Function(...variables, `return ${options.filterFct}`);
    }

    if (uniqueMFs === true) options.canonizeMF = true;
    if (options.canonizeMF === undefined) options.canonizeMF = true;
    options.ionizations = preprocessIonizations(options.ionizations);

    if (!Array.isArray(keys)) {
      throw new Error('You need to specify an array of strings or arrays');
    } // we allow String delimited by ". or ;" instead of an array


    for (let i = 0; i < keys.length; i++) {
      if (!Array.isArray(keys[i])) {
        keys[i] = keys[i].split(/[.,]/);
      }
    } // we allow ranges in a string ...
    // problem with ranges is that we need to know to what the range applies


    for (let i = 0; i < keys.length; i++) {
      let parts = keys[i];
      let newParts = [];

      for (let j = 0; j < parts.length; j++) {
        let part = parts[j];
        let comment = part.replace(/^([^$]*\$|.*)/, '');
        part = part.replace(/\$.*/, '').replace(/\s/g, '');

        if (part.match(/[0-9]-[0-9-]/)) {
          // deal with negative numbers
          // there are ranges ... we are in trouble !
          newParts = newParts.concat(processRange_1(part, comment, {
            limit
          }));
        } else {
          newParts.push(parts[j]); // the part with the comments !
        }
      }

      keys[i] = newParts;
    }

    if (estimate) {
      let total = keys.reduce((previous, current) => previous * current.length, 1);
      return total * options.ionizations.length;
    }

    let results = [];
    let sizes = [];
    let currents = [];

    for (let i = 0; i < keys.length; i++) {
      sizes.push(keys[i].length - 1);
      currents.push(0);
    }

    let position = 0;
    let evolution = 0;

    while (position < currents.length) {
      if (currents[position] < sizes[position]) {
        evolution++;
        appendResult(results, currents, keys, options);
        currents[position]++;

        for (let i = 0; i < position; i++) {
          currents[i] = 0;
        }

        position = 0;
      } else {
        position++;
      }

      if (evolution > limit) {
        throw new Error(`You have reached the limit of ${limit}. You could still change this value using the limit option but it is likely to crash.`);
      }
    }

    appendResult(results, currents, keys, options);

    if (uniqueMFs) {
      let uniqueMFsObject = {};
      results.forEach(result => {
        uniqueMFsObject[result.mf + result.ionization.mf] = result;
      });
      results = Object.keys(uniqueMFsObject).map(k => uniqueMFsObject[k]);
    }

    results.sort((a, b) => a.em - b.em);
    return results;
  };

  let ems = {}; // internal method used as a cache

  function getMonoisotopicMass(mfString) {
    if (!ems[mfString]) {
      // we need to calculate based on the mf but not very often ...
      let mf = new MF$2(mfString);
      let info = mf.getInfo();
      ems[mfString] = {
        em: info.monoisotopicMass,
        charge: info.charge,
        mw: info.mass,
        unsaturation: (info.unsaturation - 1) * 2,
        atoms: info.atoms
      };
    }

    return ems[mfString];
  }

  function getEMFromParts(parts, currents, ionization) {
    let charge = 0;
    let em = 0;
    let mw = 0;
    let unsaturation = 0;
    let validUnsaturation = true;
    let atoms = {};

    for (let i = 0; i < parts.length; i++) {
      let part = parts[i][currents[i]];

      if (part) {
        let info = getMonoisotopicMass(part);
        charge += info.charge;
        em += info.em;
        mw += info.mw;
        lib$3(atoms, info.atoms);

        if (info.unsaturation && validUnsaturation) {
          unsaturation += info.unsaturation;
        }
      }
    }

    return {
      charge,
      em,
      mw,
      ionization: ionization,
      unsaturation: unsaturation / 2 + 1 ,
      atoms
    };
  }

  function appendResult(results, currents, keys, options = {}) {
    const {
      canonizeMF,
      filter,
      ionizations,
      links = {}
    } = options; // this script is designed to combine molecular formula
    // that may contain comments after a "$" sign
    // therefore we should put all the comments at the ned

    if (links.filter) {
      let stars = [];

      for (let i = 0; i < keys.length; i++) {
        let anchors = keys[i][currents[i]].match(/#[0-9]+/g);
        if (anchors) stars.push(...anchors);
      }

      if (stars.length % 2 === 1) return;
      stars = stars.sort();

      for (let i = 0; i < stars.length; i += 2) {
        if (stars[i] !== stars[i + 1]) return;
      }
    }

    for (let ionization of ionizations) {
      let result = getEMFromParts(keys, currents, ionization);

      if (options.filterFct) {
        let variables = [];

        for (let key in options.filterFctVariables) {
          variables.push(currents[options.filterFctVariables[key]]);
        }

        variables.push(result.em, (result.em + ionization.em - ionization.charge * ELECTRON_MASS$3) / Math.abs(ionization.charge), result.charge + result.ionization.charge, result.unsaturation, result.atoms);
        if (!options.filterFct.apply(null, variables)) continue;
      }

      let match = matcher$2(result, filter);
      if (!match) continue;
      result.ms = match.ms;
      result.ionization = match.ionization;
      result.parts = [];
      result.mf = '';
      let comments = [];

      for (let i = 0; i < keys.length; i++) {
        let key = keys[i][currents[i]];

        if (key) {
          if (key.indexOf('$') > -1) {
            comments.push(key.replace(/^[^$]*\$/, ''));
            key = key.replace(/\$.*/, '');
          }

          result.parts[i] = key;
          result.mf += key;
        }
      }

      if (canonizeMF) {
        result.mf = new MF$2(result.mf).toMF();
      }

      if (comments.length > 0) {
        result.comment = comments.join(' ');
      }

      results.push(result);
    }
  }

  /* @license
  Papa Parse
  v5.3.1
  https://github.com/mholt/PapaParse
  License: MIT
  */
  var papaparse_min = createCommonjsModule$1(function (module, exports) {
    !function (e, t) {
      module.exports = t() ;
    }(commonjsGlobal$1, function s() {

      var f = "undefined" != typeof self ? self : "undefined" != typeof window ? window : void 0 !== f ? f : {};
      var n = !f.document && !!f.postMessage,
          o = n && /blob:/i.test((f.location || {}).protocol),
          a = {},
          h = 0,
          b = {
        parse: function (e, t) {
          var i = (t = t || {}).dynamicTyping || !1;
          M(i) && (t.dynamicTypingFunction = i, i = {});

          if (t.dynamicTyping = i, t.transform = !!M(t.transform) && t.transform, t.worker && b.WORKERS_SUPPORTED) {
            var r = function () {
              if (!b.WORKERS_SUPPORTED) return !1;
              var e = (i = f.URL || f.webkitURL || null, r = s.toString(), b.BLOB_URL || (b.BLOB_URL = i.createObjectURL(new Blob(["(", r, ")();"], {
                type: "text/javascript"
              })))),
                  t = new f.Worker(e);
              var i, r;
              return t.onmessage = _, t.id = h++, a[t.id] = t;
            }();

            return r.userStep = t.step, r.userChunk = t.chunk, r.userComplete = t.complete, r.userError = t.error, t.step = M(t.step), t.chunk = M(t.chunk), t.complete = M(t.complete), t.error = M(t.error), delete t.worker, void r.postMessage({
              input: e,
              config: t,
              workerId: r.id
            });
          }

          var n = null;
          b.NODE_STREAM_INPUT, "string" == typeof e ? n = t.download ? new l(t) : new p(t) : !0 === e.readable && M(e.read) && M(e.on) ? n = new g(t) : (f.File && e instanceof File || e instanceof Object) && (n = new c(t));
          return n.stream(e);
        },
        unparse: function (e, t) {
          var n = !1,
              _ = !0,
              m = ",",
              y = "\r\n",
              s = '"',
              a = s + s,
              i = !1,
              r = null,
              o = !1;

          !function () {
            if ("object" != typeof t) return;
            "string" != typeof t.delimiter || b.BAD_DELIMITERS.filter(function (e) {
              return -1 !== t.delimiter.indexOf(e);
            }).length || (m = t.delimiter);
            ("boolean" == typeof t.quotes || "function" == typeof t.quotes || Array.isArray(t.quotes)) && (n = t.quotes);
            "boolean" != typeof t.skipEmptyLines && "string" != typeof t.skipEmptyLines || (i = t.skipEmptyLines);
            "string" == typeof t.newline && (y = t.newline);
            "string" == typeof t.quoteChar && (s = t.quoteChar);
            "boolean" == typeof t.header && (_ = t.header);

            if (Array.isArray(t.columns)) {
              if (0 === t.columns.length) throw new Error("Option columns is empty");
              r = t.columns;
            }

            void 0 !== t.escapeChar && (a = t.escapeChar + s);
            "boolean" == typeof t.escapeFormulae && (o = t.escapeFormulae);
          }();
          var h = new RegExp(j(s), "g");
          "string" == typeof e && (e = JSON.parse(e));

          if (Array.isArray(e)) {
            if (!e.length || Array.isArray(e[0])) return u(null, e, i);
            if ("object" == typeof e[0]) return u(r || Object.keys(e[0]), e, i);
          } else if ("object" == typeof e) return "string" == typeof e.data && (e.data = JSON.parse(e.data)), Array.isArray(e.data) && (e.fields || (e.fields = e.meta && e.meta.fields), e.fields || (e.fields = Array.isArray(e.data[0]) ? e.fields : "object" == typeof e.data[0] ? Object.keys(e.data[0]) : []), Array.isArray(e.data[0]) || "object" == typeof e.data[0] || (e.data = [e.data])), u(e.fields || [], e.data || [], i);

          throw new Error("Unable to serialize unrecognized input");

          function u(e, t, i) {
            var r = "";
            "string" == typeof e && (e = JSON.parse(e)), "string" == typeof t && (t = JSON.parse(t));
            var n = Array.isArray(e) && 0 < e.length,
                s = !Array.isArray(t[0]);

            if (n && _) {
              for (var a = 0; a < e.length; a++) 0 < a && (r += m), r += v(e[a], a);

              0 < t.length && (r += y);
            }

            for (var o = 0; o < t.length; o++) {
              var h = n ? e.length : t[o].length,
                  u = !1,
                  f = n ? 0 === Object.keys(t[o]).length : 0 === t[o].length;

              if (i && !n && (u = "greedy" === i ? "" === t[o].join("").trim() : 1 === t[o].length && 0 === t[o][0].length), "greedy" === i && n) {
                for (var d = [], l = 0; l < h; l++) {
                  var c = s ? e[l] : l;
                  d.push(t[o][c]);
                }

                u = "" === d.join("").trim();
              }

              if (!u) {
                for (var p = 0; p < h; p++) {
                  0 < p && !f && (r += m);
                  var g = n && s ? e[p] : p;
                  r += v(t[o][g], p);
                }

                o < t.length - 1 && (!i || 0 < h && !f) && (r += y);
              }
            }

            return r;
          }

          function v(e, t) {
            if (null == e) return "";
            if (e.constructor === Date) return JSON.stringify(e).slice(1, 25);
            !0 === o && "string" == typeof e && null !== e.match(/^[=+\-@].*$/) && (e = "'" + e);

            var i = e.toString().replace(h, a),
                r = "boolean" == typeof n && n || "function" == typeof n && n(e, t) || Array.isArray(n) && n[t] || function (e, t) {
              for (var i = 0; i < t.length; i++) if (-1 < e.indexOf(t[i])) return !0;

              return !1;
            }(i, b.BAD_DELIMITERS) || -1 < i.indexOf(m) || " " === i.charAt(0) || " " === i.charAt(i.length - 1);

            return r ? s + i + s : i;
          }
        }
      };

      if (b.RECORD_SEP = String.fromCharCode(30), b.UNIT_SEP = String.fromCharCode(31), b.BYTE_ORDER_MARK = "\ufeff", b.BAD_DELIMITERS = ["\r", "\n", '"', b.BYTE_ORDER_MARK], b.WORKERS_SUPPORTED = !n && !!f.Worker, b.NODE_STREAM_INPUT = 1, b.LocalChunkSize = 10485760, b.RemoteChunkSize = 5242880, b.DefaultDelimiter = ",", b.Parser = E, b.ParserHandle = i, b.NetworkStreamer = l, b.FileStreamer = c, b.StringStreamer = p, b.ReadableStreamStreamer = g, f.jQuery) {
        var d = f.jQuery;

        d.fn.parse = function (o) {
          var i = o.config || {},
              h = [];
          return this.each(function (e) {
            if (!("INPUT" === d(this).prop("tagName").toUpperCase() && "file" === d(this).attr("type").toLowerCase() && f.FileReader) || !this.files || 0 === this.files.length) return !0;

            for (var t = 0; t < this.files.length; t++) h.push({
              file: this.files[t],
              inputElem: this,
              instanceConfig: d.extend({}, i)
            });
          }), e(), this;

          function e() {
            if (0 !== h.length) {
              var e,
                  t,
                  i,
                  r,
                  n = h[0];

              if (M(o.before)) {
                var s = o.before(n.file, n.inputElem);

                if ("object" == typeof s) {
                  if ("abort" === s.action) return e = "AbortError", t = n.file, i = n.inputElem, r = s.reason, void (M(o.error) && o.error({
                    name: e
                  }, t, i, r));
                  if ("skip" === s.action) return void u();
                  "object" == typeof s.config && (n.instanceConfig = d.extend(n.instanceConfig, s.config));
                } else if ("skip" === s) return void u();
              }

              var a = n.instanceConfig.complete;
              n.instanceConfig.complete = function (e) {
                M(a) && a(e, n.file, n.inputElem), u();
              }, b.parse(n.file, n.instanceConfig);
            } else M(o.complete) && o.complete();
          }

          function u() {
            h.splice(0, 1), e();
          }
        };
      }

      function u(e) {
        this._handle = null, this._finished = !1, this._completed = !1, this._halted = !1, this._input = null, this._baseIndex = 0, this._partialLine = "", this._rowCount = 0, this._start = 0, this._nextChunk = null, this.isFirstChunk = !0, this._completeResults = {
          data: [],
          errors: [],
          meta: {}
        }, function (e) {
          var t = w(e);
          t.chunkSize = parseInt(t.chunkSize), e.step || e.chunk || (t.chunkSize = null);
          this._handle = new i(t), (this._handle.streamer = this)._config = t;
        }.call(this, e), this.parseChunk = function (e, t) {
          if (this.isFirstChunk && M(this._config.beforeFirstChunk)) {
            var i = this._config.beforeFirstChunk(e);

            void 0 !== i && (e = i);
          }

          this.isFirstChunk = !1, this._halted = !1;
          var r = this._partialLine + e;
          this._partialLine = "";

          var n = this._handle.parse(r, this._baseIndex, !this._finished);

          if (!this._handle.paused() && !this._handle.aborted()) {
            var s = n.meta.cursor;
            this._finished || (this._partialLine = r.substring(s - this._baseIndex), this._baseIndex = s), n && n.data && (this._rowCount += n.data.length);
            var a = this._finished || this._config.preview && this._rowCount >= this._config.preview;
            if (o) f.postMessage({
              results: n,
              workerId: b.WORKER_ID,
              finished: a
            });else if (M(this._config.chunk) && !t) {
              if (this._config.chunk(n, this._handle), this._handle.paused() || this._handle.aborted()) return void (this._halted = !0);
              n = void 0, this._completeResults = void 0;
            }
            return this._config.step || this._config.chunk || (this._completeResults.data = this._completeResults.data.concat(n.data), this._completeResults.errors = this._completeResults.errors.concat(n.errors), this._completeResults.meta = n.meta), this._completed || !a || !M(this._config.complete) || n && n.meta.aborted || (this._config.complete(this._completeResults, this._input), this._completed = !0), a || n && n.meta.paused || this._nextChunk(), n;
          }

          this._halted = !0;
        }, this._sendError = function (e) {
          M(this._config.error) ? this._config.error(e) : o && this._config.error && f.postMessage({
            workerId: b.WORKER_ID,
            error: e,
            finished: !1
          });
        };
      }

      function l(e) {
        var r;
        (e = e || {}).chunkSize || (e.chunkSize = b.RemoteChunkSize), u.call(this, e), this._nextChunk = n ? function () {
          this._readChunk(), this._chunkLoaded();
        } : function () {
          this._readChunk();
        }, this.stream = function (e) {
          this._input = e, this._nextChunk();
        }, this._readChunk = function () {
          if (this._finished) this._chunkLoaded();else {
            if (r = new XMLHttpRequest(), this._config.withCredentials && (r.withCredentials = this._config.withCredentials), n || (r.onload = v(this._chunkLoaded, this), r.onerror = v(this._chunkError, this)), r.open(this._config.downloadRequestBody ? "POST" : "GET", this._input, !n), this._config.downloadRequestHeaders) {
              var e = this._config.downloadRequestHeaders;

              for (var t in e) r.setRequestHeader(t, e[t]);
            }

            if (this._config.chunkSize) {
              var i = this._start + this._config.chunkSize - 1;
              r.setRequestHeader("Range", "bytes=" + this._start + "-" + i);
            }

            try {
              r.send(this._config.downloadRequestBody);
            } catch (e) {
              this._chunkError(e.message);
            }

            n && 0 === r.status && this._chunkError();
          }
        }, this._chunkLoaded = function () {
          4 === r.readyState && (r.status < 200 || 400 <= r.status ? this._chunkError() : (this._start += this._config.chunkSize ? this._config.chunkSize : r.responseText.length, this._finished = !this._config.chunkSize || this._start >= function (e) {
            var t = e.getResponseHeader("Content-Range");
            if (null === t) return -1;
            return parseInt(t.substring(t.lastIndexOf("/") + 1));
          }(r), this.parseChunk(r.responseText)));
        }, this._chunkError = function (e) {
          var t = r.statusText || e;

          this._sendError(new Error(t));
        };
      }

      function c(e) {
        var r, n;
        (e = e || {}).chunkSize || (e.chunkSize = b.LocalChunkSize), u.call(this, e);
        var s = "undefined" != typeof FileReader;
        this.stream = function (e) {
          this._input = e, n = e.slice || e.webkitSlice || e.mozSlice, s ? ((r = new FileReader()).onload = v(this._chunkLoaded, this), r.onerror = v(this._chunkError, this)) : r = new FileReaderSync(), this._nextChunk();
        }, this._nextChunk = function () {
          this._finished || this._config.preview && !(this._rowCount < this._config.preview) || this._readChunk();
        }, this._readChunk = function () {
          var e = this._input;

          if (this._config.chunkSize) {
            var t = Math.min(this._start + this._config.chunkSize, this._input.size);
            e = n.call(e, this._start, t);
          }

          var i = r.readAsText(e, this._config.encoding);
          s || this._chunkLoaded({
            target: {
              result: i
            }
          });
        }, this._chunkLoaded = function (e) {
          this._start += this._config.chunkSize, this._finished = !this._config.chunkSize || this._start >= this._input.size, this.parseChunk(e.target.result);
        }, this._chunkError = function () {
          this._sendError(r.error);
        };
      }

      function p(e) {
        var i;
        u.call(this, e = e || {}), this.stream = function (e) {
          return i = e, this._nextChunk();
        }, this._nextChunk = function () {
          if (!this._finished) {
            var e,
                t = this._config.chunkSize;
            return t ? (e = i.substring(0, t), i = i.substring(t)) : (e = i, i = ""), this._finished = !i, this.parseChunk(e);
          }
        };
      }

      function g(e) {
        u.call(this, e = e || {});
        var t = [],
            i = !0,
            r = !1;
        this.pause = function () {
          u.prototype.pause.apply(this, arguments), this._input.pause();
        }, this.resume = function () {
          u.prototype.resume.apply(this, arguments), this._input.resume();
        }, this.stream = function (e) {
          this._input = e, this._input.on("data", this._streamData), this._input.on("end", this._streamEnd), this._input.on("error", this._streamError);
        }, this._checkIsFinished = function () {
          r && 1 === t.length && (this._finished = !0);
        }, this._nextChunk = function () {
          this._checkIsFinished(), t.length ? this.parseChunk(t.shift()) : i = !0;
        }, this._streamData = v(function (e) {
          try {
            t.push("string" == typeof e ? e : e.toString(this._config.encoding)), i && (i = !1, this._checkIsFinished(), this.parseChunk(t.shift()));
          } catch (e) {
            this._streamError(e);
          }
        }, this), this._streamError = v(function (e) {
          this._streamCleanUp(), this._sendError(e);
        }, this), this._streamEnd = v(function () {
          this._streamCleanUp(), r = !0, this._streamData("");
        }, this), this._streamCleanUp = v(function () {
          this._input.removeListener("data", this._streamData), this._input.removeListener("end", this._streamEnd), this._input.removeListener("error", this._streamError);
        }, this);
      }

      function i(m) {
        var a,
            o,
            h,
            r = Math.pow(2, 53),
            n = -r,
            s = /^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/,
            u = /^(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))$/,
            t = this,
            i = 0,
            f = 0,
            d = !1,
            e = !1,
            l = [],
            c = {
          data: [],
          errors: [],
          meta: {}
        };

        if (M(m.step)) {
          var p = m.step;

          m.step = function (e) {
            if (c = e, _()) g();else {
              if (g(), 0 === c.data.length) return;
              i += e.data.length, m.preview && i > m.preview ? o.abort() : (c.data = c.data[0], p(c, t));
            }
          };
        }

        function y(e) {
          return "greedy" === m.skipEmptyLines ? "" === e.join("").trim() : 1 === e.length && 0 === e[0].length;
        }

        function g() {
          if (c && h && (k("Delimiter", "UndetectableDelimiter", "Unable to auto-detect delimiting character; defaulted to '" + b.DefaultDelimiter + "'"), h = !1), m.skipEmptyLines) for (var e = 0; e < c.data.length; e++) y(c.data[e]) && c.data.splice(e--, 1);
          return _() && function () {
            if (!c) return;

            function e(e, t) {
              M(m.transformHeader) && (e = m.transformHeader(e, t)), l.push(e);
            }

            if (Array.isArray(c.data[0])) {
              for (var t = 0; _() && t < c.data.length; t++) c.data[t].forEach(e);

              c.data.splice(0, 1);
            } else c.data.forEach(e);
          }(), function () {
            if (!c || !m.header && !m.dynamicTyping && !m.transform) return c;

            function e(e, t) {
              var i,
                  r = m.header ? {} : [];

              for (i = 0; i < e.length; i++) {
                var n = i,
                    s = e[i];
                m.header && (n = i >= l.length ? "__parsed_extra" : l[i]), m.transform && (s = m.transform(s, n)), s = v(n, s), "__parsed_extra" === n ? (r[n] = r[n] || [], r[n].push(s)) : r[n] = s;
              }

              return m.header && (i > l.length ? k("FieldMismatch", "TooManyFields", "Too many fields: expected " + l.length + " fields but parsed " + i, f + t) : i < l.length && k("FieldMismatch", "TooFewFields", "Too few fields: expected " + l.length + " fields but parsed " + i, f + t)), r;
            }

            var t = 1;
            !c.data.length || Array.isArray(c.data[0]) ? (c.data = c.data.map(e), t = c.data.length) : c.data = e(c.data, 0);
            m.header && c.meta && (c.meta.fields = l);
            return f += t, c;
          }();
        }

        function _() {
          return m.header && 0 === l.length;
        }

        function v(e, t) {
          return i = e, m.dynamicTypingFunction && void 0 === m.dynamicTyping[i] && (m.dynamicTyping[i] = m.dynamicTypingFunction(i)), !0 === (m.dynamicTyping[i] || m.dynamicTyping) ? "true" === t || "TRUE" === t || "false" !== t && "FALSE" !== t && (function (e) {
            if (s.test(e)) {
              var t = parseFloat(e);
              if (n < t && t < r) return !0;
            }

            return !1;
          }(t) ? parseFloat(t) : u.test(t) ? new Date(t) : "" === t ? null : t) : t;
          var i;
        }

        function k(e, t, i, r) {
          var n = {
            type: e,
            code: t,
            message: i
          };
          void 0 !== r && (n.row = r), c.errors.push(n);
        }

        this.parse = function (e, t, i) {
          var r = m.quoteChar || '"';
          if (m.newline || (m.newline = function (e, t) {
            e = e.substring(0, 1048576);
            var i = new RegExp(j(t) + "([^]*?)" + j(t), "gm"),
                r = (e = e.replace(i, "")).split("\r"),
                n = e.split("\n"),
                s = 1 < n.length && n[0].length < r[0].length;
            if (1 === r.length || s) return "\n";

            for (var a = 0, o = 0; o < r.length; o++) "\n" === r[o][0] && a++;

            return a >= r.length / 2 ? "\r\n" : "\r";
          }(e, r)), h = !1, m.delimiter) M(m.delimiter) && (m.delimiter = m.delimiter(e), c.meta.delimiter = m.delimiter);else {
            var n = function (e, t, i, r, n) {
              var s, a, o, h;
              n = n || [",", "\t", "|", ";", b.RECORD_SEP, b.UNIT_SEP];

              for (var u = 0; u < n.length; u++) {
                var f = n[u],
                    d = 0,
                    l = 0,
                    c = 0;
                o = void 0;

                for (var p = new E({
                  comments: r,
                  delimiter: f,
                  newline: t,
                  preview: 10
                }).parse(e), g = 0; g < p.data.length; g++) if (i && y(p.data[g])) c++;else {
                  var _ = p.data[g].length;
                  l += _, void 0 !== o ? 0 < _ && (d += Math.abs(_ - o), o = _) : o = _;
                }

                0 < p.data.length && (l /= p.data.length - c), (void 0 === a || d <= a) && (void 0 === h || h < l) && 1.99 < l && (a = d, s = f, h = l);
              }

              return {
                successful: !!(m.delimiter = s),
                bestDelimiter: s
              };
            }(e, m.newline, m.skipEmptyLines, m.comments, m.delimitersToGuess);

            n.successful ? m.delimiter = n.bestDelimiter : (h = !0, m.delimiter = b.DefaultDelimiter), c.meta.delimiter = m.delimiter;
          }
          var s = w(m);
          return m.preview && m.header && s.preview++, a = e, o = new E(s), c = o.parse(a, t, i), g(), d ? {
            meta: {
              paused: !0
            }
          } : c || {
            meta: {
              paused: !1
            }
          };
        }, this.paused = function () {
          return d;
        }, this.pause = function () {
          d = !0, o.abort(), a = M(m.chunk) ? "" : a.substring(o.getCharIndex());
        }, this.resume = function () {
          t.streamer._halted ? (d = !1, t.streamer.parseChunk(a, !0)) : setTimeout(t.resume, 3);
        }, this.aborted = function () {
          return e;
        }, this.abort = function () {
          e = !0, o.abort(), c.meta.aborted = !0, M(m.complete) && m.complete(c), a = "";
        };
      }

      function j(e) {
        return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
      }

      function E(e) {
        var S,
            O = (e = e || {}).delimiter,
            x = e.newline,
            I = e.comments,
            T = e.step,
            D = e.preview,
            A = e.fastMode,
            L = S = void 0 === e.quoteChar ? '"' : e.quoteChar;
        if (void 0 !== e.escapeChar && (L = e.escapeChar), ("string" != typeof O || -1 < b.BAD_DELIMITERS.indexOf(O)) && (O = ","), I === O) throw new Error("Comment character same as delimiter");
        !0 === I ? I = "#" : ("string" != typeof I || -1 < b.BAD_DELIMITERS.indexOf(I)) && (I = !1), "\n" !== x && "\r" !== x && "\r\n" !== x && (x = "\n");
        var F = 0,
            z = !1;
        this.parse = function (r, t, i) {
          if ("string" != typeof r) throw new Error("Input must be a string");
          var n = r.length,
              e = O.length,
              s = x.length,
              a = I.length,
              o = M(T),
              h = [],
              u = [],
              f = [],
              d = F = 0;
          if (!r) return C();

          if (A || !1 !== A && -1 === r.indexOf(S)) {
            for (var l = r.split(x), c = 0; c < l.length; c++) {
              if (f = l[c], F += f.length, c !== l.length - 1) F += x.length;else if (i) return C();

              if (!I || f.substring(0, a) !== I) {
                if (o) {
                  if (h = [], k(f.split(O)), R(), z) return C();
                } else k(f.split(O));

                if (D && D <= c) return h = h.slice(0, D), C(!0);
              }
            }

            return C();
          }

          for (var p = r.indexOf(O, F), g = r.indexOf(x, F), _ = new RegExp(j(L) + j(S), "g"), m = r.indexOf(S, F);;) if (r[F] !== S) {
            if (I && 0 === f.length && r.substring(F, F + a) === I) {
              if (-1 === g) return C();
              F = g + s, g = r.indexOf(x, F), p = r.indexOf(O, F);
            } else if (-1 !== p && (p < g || -1 === g)) f.push(r.substring(F, p)), F = p + e, p = r.indexOf(O, F);else {
              if (-1 === g) break;
              if (f.push(r.substring(F, g)), w(g + s), o && (R(), z)) return C();
              if (D && h.length >= D) return C(!0);
            }
          } else for (m = F, F++;;) {
            if (-1 === (m = r.indexOf(S, m + 1))) return i || u.push({
              type: "Quotes",
              code: "MissingQuotes",
              message: "Quoted field unterminated",
              row: h.length,
              index: F
            }), E();
            if (m === n - 1) return E(r.substring(F, m).replace(_, S));

            if (S !== L || r[m + 1] !== L) {
              if (S === L || 0 === m || r[m - 1] !== L) {
                -1 !== p && p < m + 1 && (p = r.indexOf(O, m + 1)), -1 !== g && g < m + 1 && (g = r.indexOf(x, m + 1));
                var y = b(-1 === g ? p : Math.min(p, g));

                if (r[m + 1 + y] === O) {
                  f.push(r.substring(F, m).replace(_, S)), r[F = m + 1 + y + e] !== S && (m = r.indexOf(S, F)), p = r.indexOf(O, F), g = r.indexOf(x, F);
                  break;
                }

                var v = b(g);

                if (r.substring(m + 1 + v, m + 1 + v + s) === x) {
                  if (f.push(r.substring(F, m).replace(_, S)), w(m + 1 + v + s), p = r.indexOf(O, F), m = r.indexOf(S, F), o && (R(), z)) return C();
                  if (D && h.length >= D) return C(!0);
                  break;
                }

                u.push({
                  type: "Quotes",
                  code: "InvalidQuotes",
                  message: "Trailing quote on quoted field is malformed",
                  row: h.length,
                  index: F
                }), m++;
              }
            } else m++;
          }

          return E();

          function k(e) {
            h.push(e), d = F;
          }

          function b(e) {
            var t = 0;

            if (-1 !== e) {
              var i = r.substring(m + 1, e);
              i && "" === i.trim() && (t = i.length);
            }

            return t;
          }

          function E(e) {
            return i || (void 0 === e && (e = r.substring(F)), f.push(e), F = n, k(f), o && R()), C();
          }

          function w(e) {
            F = e, k(f), f = [], g = r.indexOf(x, F);
          }

          function C(e) {
            return {
              data: h,
              errors: u,
              meta: {
                delimiter: O,
                linebreak: x,
                aborted: z,
                truncated: !!e,
                cursor: d + (t || 0)
              }
            };
          }

          function R() {
            T(C()), h = [], u = [];
          }
        }, this.abort = function () {
          z = !0;
        }, this.getCharIndex = function () {
          return F;
        };
      }

      function _(e) {
        var t = e.data,
            i = a[t.workerId],
            r = !1;
        if (t.error) i.userError(t.error, t.file);else if (t.results && t.results.data) {
          var n = {
            abort: function () {
              r = !0, m(t.workerId, {
                data: [],
                errors: [],
                meta: {
                  aborted: !0
                }
              });
            },
            pause: y,
            resume: y
          };

          if (M(i.userStep)) {
            for (var s = 0; s < t.results.data.length && (i.userStep({
              data: t.results.data[s],
              errors: t.results.errors,
              meta: t.results.meta
            }, n), !r); s++);

            delete t.results;
          } else M(i.userChunk) && (i.userChunk(t.results, n, t.file), delete t.results);
        }
        t.finished && !r && m(t.workerId, t.results);
      }

      function m(e, t) {
        var i = a[e];
        M(i.userComplete) && i.userComplete(t), i.terminate(), delete a[e];
      }

      function y() {
        throw new Error("Not implemented.");
      }

      function w(e) {
        if ("object" != typeof e || null === e) return e;
        var t = Array.isArray(e) ? [] : {};

        for (var i in e) t[i] = w(e[i]);

        return t;
      }

      function v(e, t) {
        return function () {
          e.apply(t, arguments);
        };
      }

      function M(e) {
        return "function" == typeof e;
      }

      return o && (f.onmessage = function (e) {
        var t = e.data;
        void 0 === b.WORKER_ID && t && (b.WORKER_ID = t.workerId);
        if ("string" == typeof t.input) f.postMessage({
          workerId: b.WORKER_ID,
          results: b.parse(t.input, t.config),
          finished: !0
        });else if (f.File && t.input instanceof File || t.input instanceof Object) {
          var i = b.parse(t.input, t.config);
          i && f.postMessage({
            workerId: b.WORKER_ID,
            results: i,
            finished: !0
          });
        }
      }), (l.prototype = Object.create(u.prototype)).constructor = l, (c.prototype = Object.create(u.prototype)).constructor = c, (p.prototype = Object.create(p.prototype)).constructor = p, (g.prototype = Object.create(u.prototype)).constructor = g, b;
    });
  });

  /* eslint-env browser */

  var fetchTextBrowser = async function fetchTextBrowser(url) {
    const result = await fetch(url);
    return result.text();
  };

  async function mfFromGoogleSheet(url, options = {}) {
    let {
      urlReferences
    } = options;

    if (urlReferences) {
      let results = await Promise.all([fetchTextBrowser(url), fetchTextBrowser(urlReferences)]);
      return parse(results[0], results[1]);
    } else {
      let result = await fetchTextBrowser(url);
      return parse(result);
    }

    function parse(tsv, tsvReferences) {
      let parsed = papaparse_min.parse(tsv, {
        delimiter: '\t',
        header: true
      });
      let fields = parsed.meta.fields;
      let infoFields = fields.filter(a => !['mf', 'modif', 'ESI', 'MALDI', 'positive', 'negative'].includes(a));
      let formulas = parsed.data;
      let references = {};

      if (tsvReferences) {
        let referencesArray = papaparse_min.parse(tsvReferences, {
          delimiter: '\t',
          header: true
        }).data;
        referencesArray.forEach(function (r) {
          references[r.label] = r;
        });
      }

      let results = [];

      for (let formula of formulas) {
        if (tsvReferences) {
          // we add references
          let refs = formula.references.split(/[ ,]+/);
          formula.references = [];

          for (let ref of refs) {
            formula.references.push(references[ref]);
          }
        } // we need to calculate all the possibilities


        try {
          let mfs = src$e([formula.mf], {
            ionizations: formula.modif
          });

          for (let mf of mfs) {
            mf.info = {};

            for (let infoField of infoFields) {
              mf.info[infoField] = formula[infoField];
            }

            if (!formula.ESI && !formula.MALDI && !formula.positive && !formula.negative) {
              mf.filter = {
                ESI: true,
                MALDI: true,
                positive: true,
                negative: true
              };
            } else {
              mf.filter = {
                ESI: formula.ESI === 'X' ? true : false,
                MALDI: formula.MALDI === 'X' ? true : false,
                positive: formula.positive === 'X' ? true : false,
                negative: formula.negative === 'X' ? true : false
              };
            }

            mf.mf = new MF_1(mf.mf).toMF();
            results.push(mf);
          }
        } catch (e) {
          // eslint-disable-next-line no-console
          console.warn('Non parsable molecular formula: ', formula.mf, formula.modif, e.toString());
        }
      }

      results = results.filter(function (a) {
        return a.ms.em !== 0;
      });
      results.sort(function (a, b) {
        return a.ms.em - b.ms.em;
      });
      let uniqueResults = [results[0]];

      for (let i = 1; i < results.length; i++) {
        if (results[i - 1].ms.em !== results[i].ms.em) {
          uniqueResults.push(results[i]);
        }
      }

      return uniqueResults;
    }
  }

  var src$d = mfFromGoogleSheet;

  var loadGoogleSheet = async function loadGoogleSheet(options = {}) {
    let {
      refUUID = '1C_H9aiJyu9M9in7sHMOaz-d3Sv758rE72oLxEKH9ioA',
      uuid = '1LrJCl9-xSZKhGA9Y8nKVkYwB-mEOHBkTXg5qYXeFpZY'
    } = options;
    if (options.uuid && !options.refUUID) refUUID = '';
    let url = `https://googledocs.cheminfo.org/spreadsheets/d/${uuid}/export?format=tsv`;
    let refURL = refUUID ? `https://googledocs.cheminfo.org/spreadsheets/d/${refUUID}/export?format=tsv` : '';
    let data = await src$d(url, refURL);
    data.sort((a, b) => a.em - b.em);
    return data;
  };

  const loadingPromises = {};

  var loadKnapSack = async function loadKnapSack(options = {}) {
    const {
      url = 'https://couch.cheminfo.org/cheminfo-public/d2eb480198c80275a1d05dd3609414f9/upload/ms.zip'
    } = options;

    if (!loadingPromises[url]) {
      loadingPromises[url] = fetchArrayBuffer(url);
    }

    const buffer = await loadingPromises[url];
    const jsZip = new jszip();
    let zip = await jsZip.loadAsync(buffer);
    let fileData = await zip.files['ms.json'].async('string');
    let data = JSON.parse(fileData);
    data.forEach(d => {
      d.url = `http://kanaya.naist.jp/knapsack_jsp/information.jsp?word=${d.id}`;
    });
    data.sort((a, b) => a.em - b.em);
    return data;
  };

  const ELECTRON_MASS$2 = constants.ELECTRON_MASS;
  /**
   * returns all the possible neutral mass for a defined experimental (targetMass) mass
   */

  let TargetMassCache = function TargetMassCache(targetMass, possibilities, options = {}) {
    const {
      allowNeutral = false,
      // msem because em in this case !
      minCharge = Number.MIN_SAFE_INTEGER,
      maxCharge = Number.MAX_SAFE_INTEGER,
      charge = 0,
      precision = 100
    } = options;
    if (!possibilities || possibilities.length === 0) return {};
    let firstPossibility = possibilities[0];
    let currentMinCharge = Math.max(minCharge, firstPossibility.minCharge + charge);
    let currentMaxCharge = Math.min(maxCharge, firstPossibility.maxCharge + charge);
    this.minCharge = currentMinCharge;
    this.maxCharge = currentMaxCharge;
    let size = this.maxCharge - this.minCharge + 1;
    this.data = [];
    let minMass = 0;
    let maxMass = 0;
    let range = targetMass * precision / 1e6;

    for (let i = 0; i < size; i++) {
      let currentCharge = i + this.minCharge;

      if (currentCharge === 0) {
        if (allowNeutral) {
          minMass = targetMass - range;
          maxMass = targetMass + range;
        } else {
          minMass = Number.MAX_SAFE_INTEGER;
          maxMass = Number.MIN_SAFE_INTEGER;
        }
      } else {
        minMass = (targetMass - range) * Math.abs(currentCharge) + ELECTRON_MASS$2 * currentCharge;
        maxMass = (targetMass + range) * Math.abs(currentCharge) + ELECTRON_MASS$2 * currentCharge;
      }

      this.data.push({
        charge: currentCharge,
        minMass,
        maxMass
      });
    }
  };

  var TargetMassCache_1 = TargetMassCache;

  TargetMassCache.prototype.getMinMass = function (charge) {
    return this.data[charge - this.minCharge] ? this.data[charge - this.minCharge].minMass : Number.MAX_SAFE_INTEGER;
  };

  TargetMassCache.prototype.getMaxMass = function (charge) {
    return this.data[charge - this.minCharge] ? this.data[charge - this.minCharge].maxMass : Number.MIN_SAFE_INTEGER;
  };

  var preprocessRanges = function preprocessRanges(ranges) {
    ranges = JSON.parse(JSON.stringify(ranges));

    if (typeof ranges === 'string') {
      // need to convert to ranges
      let parsed = parse(ranges.replace(/[\r\n\t ]/g, ''));
      let newRanges = [];
      let current = {
        mf: '',
        min: 1,
        max: 1
      }; // example ClBr2(CH2)0-2NO
      // the idea is that has long as we don't have a range we don't really care
      // there is a limitation is that the range has to be first level of parenthesis

      let parenthesisLevel = 0;
      let currentMF = ''; // start at an atom first level or a parenthesis

      for (let item of parsed) {
        switch (item.kind) {
          case Kind.ATOM:
            if (parenthesisLevel === 0 && currentMF) {
              current.mf += currentMF;
              currentMF = '';
            }

            currentMF += item.value;
            break;

          case Kind.ISOTOPE:
            if (parenthesisLevel === 0 && currentMF) {
              current.mf += currentMF;
              currentMF = '';
            }

            currentMF += `[${item.value.isotope}${item.value.atom}]`;
            break;

          case Kind.MULTIPLIER:
            if (parenthesisLevel === 0 && currentMF) {
              current.mf += currentMF + item.value;
              currentMF = '';
            } else {
              currentMF += item.value;
            }

            break;

          case Kind.MULTIPLIER_RANGE:
            if (parenthesisLevel !== 0) {
              throw new Error('Range multiplier can only be at the first level');
            }

            newRanges.push({
              mf: currentMF,
              min: item.value.from,
              max: item.value.to
            });
            currentMF = '';
            break;

          case Kind.OPENING_PARENTHESIS:
            parenthesisLevel++;
            currentMF += '(';
            break;

          case Kind.CLOSING_PARENTHESIS:
            parenthesisLevel--;
            currentMF += ')';
            break;

          default:
            throw Error(`can not preprocess ${ranges}`);
        }
      }

      if (currentMF) {
        current.mf += currentMF;
      }

      if (current.mf) {
        newRanges.push(current);
      }

      ranges = newRanges;
    }

    let possibilities = [];

    for (let i = 0; i < ranges.length; i++) {
      let range = ranges[i];
      let min = range.min === undefined ? 0 : range.min;
      let max = range.max === undefined ? 1 : range.max;
      let possibility = {
        mf: range.mf,
        originalMinCount: min,
        // value defined by the user
        originalMaxCount: max,
        // value defined by the user
        currentMinCount: min,
        currentMaxCount: max,
        currentCount: min,
        currentMonoisotopicMass: 0,
        currentCharge: 0,
        currentUnsaturation: 0,
        initialOrder: i,
        minInnerMass: 0,
        maxInnerMass: 0,
        minInnerCharge: 0,
        maxInnerCharge: 0,
        minCharge: 0,
        maxCharge: 0,
        minMass: 0,
        maxMass: 0,
        innerCharge: false
      };
      possibilities.push(possibility);
      let info = new MF_1(range.mf).getInfo();
      possibility.em = range.em || info.monoisotopicMass;
      possibility.charge = range.charge || info.charge;
      possibility.unsaturation = range.unsaturation === undefined ? (info.unsaturation - 1) * 2 : range.unsaturation;
      possibility.atoms = info.atoms;

      if (possibility.mf !== info.mf) {
        possibility.isGroup = true;
      }
    }

    possibilities = possibilities.filter(r => r.originalMinCount !== 0 || r.originalMaxCount !== 0); // we will sort the way we analyse the data
    // 1. The one possibility parameter
    // 2. The charged part
    // 3. Decreasing em

    possibilities.sort((a, b) => {
      if (a.originalMinCount === a.originalMaxCount) return -1; // should be in front, they are 'static'

      if (b.originalMinCount === b.originalMaxCount) return 1;

      if (a.charge && b.charge) {
        if (Math.abs(a.charge) > Math.abs(b.charge)) return -1;
        if (Math.abs(a.charge) < Math.abs(b.charge)) return 1;
        return b.em - a.em;
      }

      if (a.charge) return -1;
      if (b.charge) return 1;
      return b.em - a.em;
    }); // we calculate couple of fixed values

    for (let i = 0; i < possibilities.length; i++) {
      for (let j = i; j < possibilities.length; j++) {
        let possibility = possibilities[j];

        if (possibility.em > 0) {
          possibilities[i].minMass += possibility.em * possibility.originalMinCount;
          possibilities[i].maxMass += possibility.em * possibility.originalMaxCount;
        } else {
          possibilities[i].minMass += possibility.em * possibility.originalMaxCount;
          possibilities[i].maxMass += possibility.em * possibility.originalMinCount;
        }

        if (possibility.charge > 0) {
          possibilities[i].minCharge += possibility.charge * possibility.originalMinCount;
          possibilities[i].maxCharge += possibility.charge * possibility.originalMaxCount;
        } else {
          possibilities[i].minCharge += possibility.charge * possibility.originalMaxCount;
          possibilities[i].maxCharge += possibility.charge * possibility.originalMinCount;
        }
      }
    }

    for (let i = 0; i < possibilities.length; i++) {
      if (i < possibilities.length - 1) {
        let possibility = possibilities[i];
        let innerPossibility = possibilities[i + 1];
        possibility.minInnerMass = innerPossibility.minMass;
        possibility.maxInnerMass = innerPossibility.maxMass;
        possibility.minInnerCharge = innerPossibility.minCharge;
        possibility.maxInnerCharge = innerPossibility.maxCharge;

        if (possibility.minInnerCharge || possibility.maxInnerCharge) {
          possibility.innerCharge = true;
        }
      }
    }

    return possibilities;
  };

  const matcher$1 = src$f.msem;
  let targetMassCache;
  /**
   * @param {number} mass - Monoisotopic mass
   * @param {object}        [options={}]
   * @param {number}        [options.maxIterations=10000000] - Maximum number of iterations
   * @param {number}        [options.limit=1000] - Maximum number of results
   * @param {string}        [options.ionizations=''] - string containing a comma separated list of modifications
   * @param {string}        [options.ranges='C0-100 H0-100 O0-100 N0-100'] - range of mfs to search
   * @param {number}        [options.precision=100] - Allowed mass range based on precision
   * @param {number}        [options.filter.minCharge=-Infinity] - Minimal charge
   * @param {number}        [options.filter.maxCharge=+Infinity] - Maximal charge
   * @param {number}        [options.filter.unsaturation={}]
   * @param {number}        [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number}        [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number}        [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number}        [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {object}        [options.filter.atoms] - object of atom:{min, max}
   * @param {function}      [options.filter.callback] - a function to filter the MF
   */

  var src$c = function (targetMass, options = {}) {
    const {
      filter = {},
      maxIterations = 1e8,
      limit = 1000,
      allowNeutral = true,
      // if there is no msem we use em !
      ranges = [{
        mf: 'C',
        min: 0,
        max: 100
      }, {
        mf: 'H',
        min: 0,
        max: 100
      }, {
        mf: 'O',
        min: 0,
        max: 100
      }, {
        mf: 'N',
        min: 0,
        max: 100
      }]
    } = options;
    const {
      minCharge = Number.MIN_SAFE_INTEGER,
      maxCharge = Number.MAX_SAFE_INTEGER,
      unsaturation = {}
    } = filter;
    let filterUnsaturation = unsaturation ? true : false; // we calculate not the real unsaturation but the one before dividing by 2 + 1

    let fakeMinUnsaturation = unsaturation.min === undefined ? Number.MIN_SAFE_INTEGER : (unsaturation.min - 1) * 2;
    let fakeMaxUnsaturation = unsaturation.max === undefined ? Number.MAX_SAFE_INTEGER : (unsaturation.max - 1) * 2;
    let filterCharge = minCharge !== Number.MIN_SAFE_INTEGER || maxCharge !== Number.MAX_SAFE_INTEGER;
    let advancedFilter;

    if (filter.atoms || filter.callback) {
      advancedFilter = {
        atoms: filter.atoms,
        callback: filter.callback
      };
    }

    let result = {
      mfs: [],
      info: {
        numberMFEvaluated: 0,
        numberResults: 0
      }
    };
    let orderMapping = []; // used to sort the atoms
    // we need to make the processing for all the ionizations

    let ionizations = preprocessIonizations(options.ionizations);

    for (let ionization of ionizations) {
      let currentIonization = {
        currentMonoisotopicMass: ionization.em || 0,
        currentCharge: ionization.charge,
        currentUnsaturation: 0 // we don't take into account the unsaturation of the ionization agent

      }; // if (DEBUG) console.log('new ionization', ionization.mf, ionization.em, ionization.charge);
      // ionization em and charge will be used to set the first atom value

      let possibilities = preprocessRanges(ranges);
      orderMapping = getOrderMapping$1(possibilities);
      if (possibilities.length === 0) return {
        mfs: []
      };
      targetMassCache = new TargetMassCache_1(targetMass, possibilities, Object.assign({}, options, {
        charge: ionization.charge
      }));
      let theEnd = false;
      let maxPosition = possibilities.length;
      let lastPosition = possibilities.length - 1;
      let currentPosition = 0;
      let currentAtom;
      let previousAtom;
      let lastPossibility = possibilities[lastPosition];
      initializePossibilities(possibilities, currentIonization); //  if (DEBUG) console.log('possibilities', possibilities.map((a) => `${a.mf + a.originalMinCount}-${a.originalMaxCount}`));

      let isValid = false; // designed so that the first time it is not a valid solution

      while (!theEnd) {
        if (result.info.numberMFEvaluated++ > maxIterations) {
          throw Error(`Iteration number is over the current maximum of: ${maxIterations}`);
        }

        if (filterUnsaturation) {
          let unsaturationValue = lastPossibility.currentUnsaturation;
          let isOdd = Math.abs(unsaturationValue % 2);

          if (unsaturation.onlyInteger && isOdd === 1 || unsaturation.onlyNonInteger && isOdd === 0 || fakeMinUnsaturation > unsaturationValue || fakeMaxUnsaturation < unsaturationValue) {
            isValid = false;
          }
        }

        if (filterCharge && (lastPossibility.currentCharge < minCharge || lastPossibility.currentCharge > maxCharge)) {
          isValid = false;
        }

        if (isValid) {
          let minMass = targetMassCache.getMinMass(lastPossibility.currentCharge);
          let maxMass = targetMassCache.getMaxMass(lastPossibility.currentCharge);

          if (lastPossibility.currentMonoisotopicMass < minMass || lastPossibility.currentMonoisotopicMass > maxMass) {
            isValid = false;
          }
        }

        if (isValid) {
          result.info.numberResults++;
          let newResult = getResult$1(possibilities, targetMass, allowNeutral, ionization, orderMapping);

          if (advancedFilter) {
            isValid = matcher$1(newResult, advancedFilter) !== false;
          }

          if (isValid) {
            result.mfs.push(newResult);

            if (result.mfs.length > 2 * limit) {
              result.mfs.sort((a, b) => Math.abs(a.ms.ppm) - Math.abs(b.ms.ppm));
              result.mfs.length = limit;
            }
          }
        }

        isValid = true; // we need to setup all the arrays if possible

        while (currentPosition < maxPosition && currentPosition >= 0) {
          currentAtom = possibilities[currentPosition];
          previousAtom = currentPosition === 0 ? currentIonization : possibilities[currentPosition - 1];

          if (currentAtom.currentCount < currentAtom.currentMaxCount) {
            currentAtom.currentCount++;
            updateCurrentAtom(currentAtom, previousAtom);

            if (currentPosition < lastPosition) {
              currentPosition++;
              setCurrentMinMax(possibilities[currentPosition], possibilities[currentPosition - 1]);
            } else {
              break;
            }
          } else {
            currentPosition--;
          }
        }

        if (currentPosition < 0) {
          theEnd = true;
        }
      }
    }

    result.mfs.sort((a, b) => Math.abs(a.ms.ppm) - Math.abs(b.ms.ppm));

    if (result.mfs.length > limit) {
      result.mfs.length = limit;
    }

    return result;
  };

  function updateCurrentAtom(currentAtom, previousAtom) {
    currentAtom.currentMonoisotopicMass = previousAtom.currentMonoisotopicMass + currentAtom.em * currentAtom.currentCount;
    currentAtom.currentCharge = previousAtom.currentCharge + currentAtom.charge * currentAtom.currentCount;
    currentAtom.currentUnsaturation = previousAtom.currentUnsaturation + currentAtom.unsaturation * currentAtom.currentCount;
  }

  function getResult$1(possibilities, targetMass, allowNeutralMolecules, ionization, orderMapping) {
    let lastPossibility = possibilities[possibilities.length - 1];
    let result = {
      em: lastPossibility.currentMonoisotopicMass - ionization.em,
      unsaturation: lastPossibility.currentUnsaturation,
      mf: '',
      charge: lastPossibility.currentCharge - ionization.charge,
      ionization,
      atoms: {},
      groups: {}
    }; // we check that the first time we meet the ionization group it does not end
    // in the final result

    for (let i = 0; i < possibilities.length; i++) {
      let possibility = possibilities[orderMapping[i]];

      if (possibility.currentCount !== 0) {
        if (possibility.isGroup) {
          result.mf += `(${possibility.mf})`;

          if (possibility.currentCount !== 1) {
            result.mf += possibility.currentCount;
          }

          if (result.groups[possibility.mf]) {
            result.groups[possibility.mf] += possibility.currentCount;
          } else {
            result.groups[possibility.mf] = possibility.currentCount;
          }
        } else {
          result.mf += possibility.mf;

          if (possibility.currentCount !== 1) {
            result.mf += possibility.currentCount;
          }
        }

        for (let atom in possibility.atoms) {
          if (result.atoms[atom]) {
            result.atoms[atom] += possibility.atoms[atom] * possibility.currentCount;
          } else {
            result.atoms[atom] = possibility.atoms[atom] * possibility.currentCount;
          }
        }
      }
    }

    result.unsaturation = (result.unsaturation + Math.abs(result.charge)) / 2 + 1;
    result.ms = getMsInfo(result, {
      targetMass,
      allowNeutralMolecules
    }).ms;
    return result;
  }

  function setCurrentMinMax(currentAtom, previousAtom) {
    // the current min max can only be optimize if the charge will not change anymore
    if (currentAtom.innerCharge === true || currentAtom.charge !== 0) {
      currentAtom.currentMinCount = currentAtom.originalMinCount;
      currentAtom.currentMaxCount = currentAtom.originalMaxCount;
      currentAtom.currentCount = currentAtom.currentMinCount - 1;
    } else {
      // no more change of charge, we can optimize
      let currentMass = previousAtom !== undefined ? previousAtom.currentMonoisotopicMass : 0;
      let currentCharge = previousAtom !== undefined ? previousAtom.currentCharge : 0;
      currentAtom.currentMinCount = Math.max(Math.floor((targetMassCache.getMinMass(currentCharge) - currentMass - currentAtom.maxInnerMass) / currentAtom.em), currentAtom.originalMinCount);
      currentAtom.currentMaxCount = Math.min(Math.floor((targetMassCache.getMaxMass(currentCharge) - currentMass - currentAtom.minInnerMass) / currentAtom.em), currentAtom.originalMaxCount);
      currentAtom.currentCount = currentAtom.currentMinCount - 1;
    }
  }

  function initializePossibilities(possibilities, currentIonization) {
    for (let i = 0; i < possibilities.length; i++) {
      if (i === 0) {
        updateCurrentAtom(possibilities[i], currentIonization);
        setCurrentMinMax(possibilities[i], currentIonization);
      } else {
        updateCurrentAtom(possibilities[i], possibilities[i - 1]);
      }
    }
  } // eslint-disable-next-line no-unused-vars

  function getOrderMapping$1(possibilities) {
    let mapping = possibilities.map((p, i) => ({
      atom: p.mf,
      index: i
    }));
    mapping.sort((a, b) => {
      return src$i(a.atom, b.atom);
    });
    return mapping.map(a => a.index);
  }

  /**
   * Generates a database 'monoisotopic' from a monoisotopic mass and various options
   * @param {number}    mass - Monoisotopic mass
   * @param {object}    [options={}]
   * @param {number}    [options.maxIterations=10000000] - Maximum number of iterations
   * @param {number}    [options.limit=1000] - Maximum number of results
   * @param {string}    [options.ionizations=''] - string containing a comma separated list of modifications
   * @param {string}    [options.ranges='C0-100 H0-100 O0-100 N0-100'] - range of mfs to search
   * @param {number}    [options.precision=100] - Allowed mass range based on precision
   * @param {number}    [options.filter.minCharge=-Infinity] - Minimal charge
   * @param {number}    [options.filter.maxCharge=+Infinity] - Maximal charge
   * @param {number}    [options.filter.unsaturation={}]
   * @param {number}    [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number}    [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number}    [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number}    [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {object}    [options.filter.atoms] - object of atom:{min, max}
   * @param {function}  [options.filter.callback] - a function to filter the MF
   */


  var fromMonoisotopicMass = function fromMonoisotopicMass(mass, options = {}) {
    return src$c(mass, options);
  };

  /**
   * Generates a database 'generated' from an array of molecular formula
   * @param {array} mfsArray - Array of string or Array of array containing the parts to combine
   * @param {obejct} [options={}]
   * @param {boolean} [options.estimate=false] - estimate the number of MF without filters
   * @param {string} [options.databaseName='generated']
   * @param {number} [options.limit=10000000] - Maximum number of results
   * @param {boolean} [canonizeMF=true] - Canonize molecular formula
   * @param {boolean} [uniqueMFs=true] - Force canonization and make MF unique
   * @param {string} [ionizations=''] - Comma separated list of ionizations (to charge the molecule)
   * @param {number} [options.filter={}]
   * @param {number} [options.filter.minMass=0] - Minimal monoisotopic mass
   * @param {number} [options.filter.maxMass=+Infinity] - Maximal monoisotopic mass
   * @param {number} [options.filter.minEM=0] - Minimal neutral monoisotopic mass
   * @param {number} [options.filter.maxEM=+Infinity] - Maximal neutral monoisotopic mass
   * @param {number} [options.filter.minMSEM=0] - Minimal observed monoisotopic mass
   * @param {number} [options.filter.maxMSEM=+Infinity] - Maximal observed monoisotopic mass
   * @param {number} [options.filter.minCharge=-Infinity] - Minimal charge
   * @param {number} [options.filter.maxCharge=+Infinity] - Maximal charge
   *
   * @param {number} [options.filter.unsaturation={}]
   * @param {number} [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number} [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number} [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number} [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {object} [options.filter.atoms] - object of atom:{min, max}
   * @param {function} [options.filter.callback] - a function to filter the MF
   * @param {string}  [options.filterFct] - A string representing a function
   *
   * @example
   *
   * const EMDB = require('emdb');
   * let emdb = new EMDB();
   * let array = ['C1-10', 'H1-10'];
   * emdb.fromArray(array); // create a database 'generated' combining all possibilies
   * console.log(emdb.get('generated').length); // 100
   *
   * @example
   * const EMDB = require('emdb');
   * let emdb = new EMDB();
   * let array = ['C1-10 H1-10'];
   * emdb.fromArray(array); // create a database 'generated' combining all possibilies
   * console.log(emdb.get('generated').length); // 100
   *
   * @example
   * const EMDB = require('emdb');
   * let emdb = new EMDB();
   * // in case of an array of array, one of the group is allwed
   * let array = [['C1-10','H1-10'],'Cl0-1 Br0-1'];
   * emdb.fromArray(array); // create a database 'generated' combining all possibilies
   * console.log(emdb.get('generated').length); // 80
   *
   * @example
   * <script src="https://www.lactame.com/lib/mass-tools/HEAD/mass-tools.js" />
   * <script>
   *   let emdb = new MolecularFormula.EMDB();
   *   let array = ['C1-10', 'H1-10'];
   *   emdb.fromArray(array); // create a database 'generated' combining all possibilities
   *   console.log(emdb.get('generated').length); // 100
   * </script>
   *
   * // from the browser
   */


  var fromArray = function fromArray(mfsArray, options = {}) {
    return src$e(mfsArray, options);
  };

  /**
   * Generates a database 'generated' from an array of molecular formula
   * @param {string} range - a string representing the range to search
   * @param {object} [options={}]
   * @param {boolean} [options.estimate=false] - estimate the number of MF without filters
   * @param {string} [options.databaseName='generated']
   * @param {number} [options.limit=100000] - Maximum number of results
   * @param {boolean} [canonizeMF=true] - Canonize molecular formula
   * @param {boolean} [uniqueMFs=true] - Force canonization and make MF unique
   * @param {string} [ionizations=''] - Comma separated list of ionizations (to charge the molecule)
   * @param {number} [options.filter={}]
   * @param {number} [options.filter.minMass=0] - Minimal monoisotopic mass
   * @param {number} [options.filter.maxMass=+Infinity] - Maximal monoisotopic mass
   * @param {number} [options.filter.minEM=0] - Minimal neutral monoisotopic mass
   * @param {number} [options.filter.maxEM=+Infinity] - Maximal neutral monoisotopic mass
   * @param {number} [options.filter.minMSEM=0] - Minimal observed monoisotopic mass
   * @param {number} [options.filter.maxMSEM=+Infinity] - Maximal observed monoisotopic mass
   * @param {number} [options.filter.minCharge=-Infinity] - Minimal charge
   * @param {number} [options.filter.maxCharge=+Infinity] - Maximal charge
   *
   * @param {number} [options.filter.unsaturation={}]
   * @param {number} [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number} [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number} [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number} [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {function} [options.filter.callback] - a function to filter the MF
   * @param {object} [options.filter.atoms] - object of atom:{min, max}
   *
   *
   * @returns {array} - list of possible molecular formula
   *
   * @example
   * const EMDB = require('emdb');
   * let emdb = new EMDB();
   * // semi-columns separated for combination, comma for 'or'
   * emdb.fromRange('C1-10, H1-10; Cl0-1 Br0-1'); // create a database 'generated' combining all possibilies
   * console.log(emdb.get('generated').length); // 80
   */


  var fromRange = function fromRange(rangesString, options = {}) {
    let ranges = rangesString.split(/ *[;\r\n] */);

    for (let i = 0; i < ranges.length; i++) {
      let range = ranges[i];

      if (range.includes(',')) {
        ranges[i] = range.split(/ *, */);
      }
    }

    return src$e(ranges, options);
  };

  var groups$2 = [{
    "symbol": "Abu",
    "name": "2-Aminobutyric acid diradical",
    "mf": "C4H7NO",
    "kind": "",
    "ocl": {
      "value": "dazHPBPOEgEInVZjcH@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGt"
    },
    "mass": 85.10463700109551,
    "monoisotopicMass": 85.05276384961,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Acet",
    "name": "Acetyl",
    "mf": "C2H3O",
    "kind": "",
    "ocl": {
      "value": "gCaHDEeIi`@",
      "coordinates": "!BbOq~@Ha}"
    },
    "mass": 43.04469897995611,
    "monoisotopicMass": 43.01838971626,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 2
    }, {
      "symbol": "H",
      "number": 3
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Acm",
    "name": "Acetamidomethyl",
    "mf": "C3H6NO",
    "kind": "",
    "ocl": {
      "value": "gGYHDPliJuS@@",
      "coordinates": "!BbOrH_Xc|_`BH_P"
    },
    "mass": 72.08596035030448,
    "monoisotopicMass": 72.04493881738,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 3
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Adao",
    "name": "Adamantyloxy",
    "mf": "C10H15O",
    "kind": "",
    "ocl": {
      "value": "dc\\H`HAYRVeV^dUGZjjjj@@",
      "coordinates": "!B]BOXN`EP}CdB\\tbZ@Ijh~hRELdOBBp"
    },
    "mass": 151.2258752025074,
    "monoisotopicMass": 151.11229010302,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Aib",
    "name": "alpha-Aminoisobutyric acid diradical",
    "mf": "C4H7NO",
    "kind": "",
    "ocl": {
      "value": "dazHPBPOGgEInfZj@@",
      "coordinates": "!Bb@I~@Ha}b@K|uwwWbGt"
    },
    "mass": 85.10463700109551,
    "monoisotopicMass": 85.05276384961,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Ala",
    "name": "Alanine diradical",
    "mf": "C3H5NO",
    "kind": "aa",
    "oneLetter": "A",
    "alternativeOneLetter": "α",
    "ocl": {
      "value": "gNyDBaxmqR[fZjZ@",
      "coordinates": "!Bb@I~@Hb}b@I~Oxa}"
    },
    "mass": 71.07801959624871,
    "monoisotopicMass": 71.03711378515,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 3
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Arg",
    "name": "Arginine diradical",
    "mf": "C6H12N4O",
    "kind": "aa",
    "oneLetter": "R",
    "alternativeOneLetter": "ρ",
    "ocl": {
      "value": "dkLhPBgSPOEgEInWUijjihr@@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}b@I~@Ha}"
    },
    "mass": 156.18592219918227,
    "monoisotopicMass": 156.10111102405,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 4
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Argp",
    "name": "Arginine triradical",
    "mf": "C6H11N4O",
    "kind": "",
    "ocl": {
      "value": "dglhpHpil@gWDEI[UYZfjji`T@",
      "coordinates": "!BbGvHGx@bGvH@ha}bOrH_Wxb@KW_Wx@bGt"
    },
    "mass": 155.1779814451265,
    "monoisotopicMass": 155.09328599182,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 4
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Asn",
    "name": "Asparagine diradical",
    "mf": "C4H6N2O2",
    "kind": "aa",
    "oneLetter": "N",
    "alternativeOneLetter": "η",
    "ocl": {
      "value": "deeDPBeACqYqR[ezZjZL`@",
      "coordinates": "!BbGu~Ox`B_`BH_X`Bb@I~@Ha}"
    },
    "mass": 114.10280438280381,
    "monoisotopicMass": 114.04292744137999,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Asnp",
    "name": "Asparagine triradical",
    "mf": "C4H5N2O2",
    "kind": "",
    "ocl": {
      "value": "dmUDpH[E@IEqgqRVvVijjXi@@",
      "coordinates": "!Bb@JH_Wxb@JH_Wxb@KW_Wx@bGt"
    },
    "mass": 113.09486362874803,
    "monoisotopicMass": 113.03510240915,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Asp",
    "name": "Aspartic acid diradical",
    "mf": "C4H5NO3",
    "kind": "aa",
    "oneLetter": "D",
    "alternativeOneLetter": "δ",
    "ocl": {
      "value": "defLPBPYCqYqR[ezZjZL`@",
      "coordinates": "!BbGu~Ox`B_`BH_X`Bb@I~@Ha}"
    },
    "mass": 115.08756534162052,
    "monoisotopicMass": 115.02694302429,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Aspp",
    "name": "Aspartic acid triradical",
    "mf": "C4H4NO3",
    "kind": "",
    "ocl": {
      "value": "dmVLpFcE@IEqgqRVvVijjXi@@",
      "coordinates": "!Bb@JH_Wxb@JH_Wxb@KW_Wx@bGt"
    },
    "mass": 114.07962458756472,
    "monoisotopicMass": 114.01911799206,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 4
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Asu",
    "name": "alpha-Aminosuberic acid diradical",
    "mf": "C8H13NO3",
    "kind": "",
    "ocl": {
      "value": "dgnLPBP{CqYqR[euVfjjihr@@",
      "coordinates": "!BbGu~Ox`B_`BH_Xc|bOrH_X`BbGvHGx@bGt"
    },
    "mass": 171.19403496100773,
    "monoisotopicMass": 171.08954328213002,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Asup",
    "name": "alpha-Aminosuberic acid triradical",
    "mf": "C8H12NO3",
    "kind": "",
    "ocl": {
      "value": "do^LpEcG@IMqoqRVuUejZjjibT@",
      "coordinates": "!BbOrH_Wxb@JH_Xc|bGvHHa}_c~H@m]}_`BH_P"
    },
    "mass": 170.18609420695194,
    "monoisotopicMass": 170.0817182499,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Boc",
    "name": "t-Butoxycarbonyl",
    "mf": "C5H9O2",
    "kind": "",
    "ocl": {
      "value": "daxD`DpEeImjZj@@",
      "coordinates": "!B|Ou~_A||Ow}mC}_O@"
    },
    "mass": 101.12395611881479,
    "monoisotopicMass": 101.06025452921,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Bom",
    "name": "Benzyloxymethyl",
    "mf": "C8H9O",
    "kind": "",
    "ocl": {
      "value": "deTH`DAYRUYTYj`@@@",
      "coordinates": "!B|Gsp__A||Owp_Gy|Gwp_Wy"
    },
    "mass": 121.15675888470227,
    "monoisotopicMass": 121.06533990964,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Brz",
    "name": "2-Bromobenzyloxycarbonyl",
    "mf": "C8H6BrO2",
    "kind": "",
    "ocl": {
      "value": "dcLDPDpEd\\QImYgWYjB@@@",
      "coordinates": "!Bb@I~@Hb}b@JH_X`B_c}~@Hb}bGu~Op"
    },
    "mass": 214.03586932736317,
    "monoisotopicMass": 212.95511703252,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "Br",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Bu",
    "name": "Butyl",
    "mf": "C4H9",
    "kind": "",
    "ocl": {
      "value": "gJPH@liJuP@",
      "coordinates": "!B@Fp@XpAl@FL"
    },
    "mass": 57.114410373442986,
    "monoisotopicMass": 57.07042529007,
    "unsaturation": -1,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 9
    }]
  }, {
    "symbol": "Bum",
    "name": "t-Butoxymethyl",
    "mf": "C5H11O",
    "kind": "",
    "ocl": {
      "value": "gNqHDEeIVjj`@",
      "coordinates": "!B@FL@[@AcXs|@Xvp@"
    },
    "mass": 87.14043270260808,
    "monoisotopicMass": 87.08098997409999,
    "unsaturation": -1,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Bz",
    "name": "Benzoyl",
    "mf": "C7H5O",
    "kind": "",
    "ocl": {
      "value": "didH`DAYR[e^FX@@@@",
      "coordinates": "!BbOq~@Ha}b@I~Oxa}bGu~Op"
    },
    "mass": 105.1142599717439,
    "monoisotopicMass": 105.03403978072,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Bzl",
    "name": "Benzyl",
    "mf": "C7H7",
    "kind": "",
    "ocl": {
      "value": "daD@`@VTeeVz`@@@",
      "coordinates": "!B|Gsp_A|_gp_A}_g|"
    },
    "mass": 91.13073655553718,
    "monoisotopicMass": 91.05477522561,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 7
    }]
  }, {
    "symbol": "Bn",
    "name": "Benzyl",
    "mf": "C7H7",
    "kind": "",
    "ocl": {
      "value": "daD@`@VTeeVz`@@@",
      "coordinates": "!B|Gsp_A|_gp_A}_g|"
    },
    "mass": 91.13073655553718,
    "monoisotopicMass": 91.05477522561,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 7
    }]
  }, {
    "symbol": "Bzlo",
    "name": "Benzyloxy",
    "mf": "C7H7O",
    "kind": "",
    "ocl": {
      "value": "didH`HAYRUe^Fh@@@@",
      "coordinates": "!B|Gwp_OC}|Gq~_A}|Gu~_p"
    },
    "mass": 107.13014147985547,
    "monoisotopicMass": 107.04968984518,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Cha",
    "name": "beta-Cyclohexylalanine diradical",
    "mf": "C9H15NO",
    "kind": "",
    "ocl": {
      "value": "dknHPBPOEgEInWe]NZjjjcH@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvH@gxbGvH_Wx"
    },
    "mass": 153.22184251721796,
    "monoisotopicMass": 153.11536410745,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Chxo",
    "name": "Cyclohexyloxy",
    "mf": "C6H11O",
    "kind": "",
    "ocl": {
      "value": "daDH`HAYRVU[jjj@@",
      "coordinates": "!B|Gsp_A|_gp_A}_g|"
    },
    "mass": 99.15116859934332,
    "monoisotopicMass": 99.08098997409999,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Cit",
    "name": "Citrulline diradical",
    "mf": "C6H11N3O2",
    "kind": "",
    "ocl": {
      "value": "dkODPBdttOEgEInWUijjihr@@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}b@I~@Ha}"
    },
    "mass": 157.170683157999,
    "monoisotopicMass": 157.08512660696,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Citp",
    "name": "Citrulline triradical",
    "mf": "C6H10N3O2",
    "kind": "",
    "ocl": {
      "value": "dgoDpHJ\\l@gWDEI[UYZfjji`T@",
      "coordinates": "!BbGvHGx@bGvH@ha}bOrH_Wxb@KW_Wx@bGt"
    },
    "mass": 156.16274240394318,
    "monoisotopicMass": 156.07730157473,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 10
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Clz",
    "name": "2-Chlorobenzyloxycarbonyl",
    "mf": "C8H6ClO2",
    "kind": "",
    "ocl": {
      "value": "dcLDPDpEdXaImYgWYjB@@@",
      "coordinates": "!Bb@I~@Hb}b@JH_X`B_c}~@Hb}bGu~Op"
    },
    "mass": 169.58527912946118,
    "monoisotopicMass": 169.00563211451998,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "Cl",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Cp",
    "name": "Cyclopentadienyl",
    "mf": "C5H5",
    "kind": "",
    "ocl": {
      "value": "gFpH@liLimRp@",
      "coordinates": "!B\\OtPThyEGl@fP"
    },
    "mass": 65.09338325395512,
    "monoisotopicMass": 65.03912516115,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 5
    }]
  }, {
    "symbol": "Cys",
    "name": "Cysteine diradical",
    "mf": "C3H5NOS",
    "kind": "aa",
    "oneLetter": "C",
    "alternativeOneLetter": "ς",
    "ocl": {
      "value": "dazHpBPOEgG`aInVZjcH@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGt"
    },
    "mass": 103.14280700237578,
    "monoisotopicMass": 103.00918495955,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 3
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Cysp",
    "name": "Cysteine triradical",
    "mf": "C3H4NOS",
    "kind": "",
    "ocl": {
      "value": "diFHHBD@f@agGoEIVVjjfLP@",
      "coordinates": "!BbGvHHa}_c~HM]}_`BH_P"
    },
    "mass": 102.13486624831998,
    "monoisotopicMass": 102.00135992732,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 3
    }, {
      "symbol": "H",
      "number": 4
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "D",
    "name": "Deuterium",
    "mf": "[2H]",
    "kind": "",
    "ocl": {
      "value": "eFAAYhBLCEH@",
      "coordinates": "!B@FL"
    },
    "mass": 2.01410177812,
    "monoisotopicMass": 2.01410177812,
    "unsaturation": -1,
    "elements": [{
      "symbol": "H",
      "number": 1,
      "isotope": 2
    }]
  }, {
    "symbol": "Dde",
    "name": "Dde",
    "mf": "C10H13O2",
    "kind": "",
    "ocl": {
      "value": "dklD`FDEgHhihicIVZfZj@@",
      "coordinates": "!Bb@I~@Ha}upJH@m]}_`BH_Wx@b@I}bOrH"
    },
    "mass": 165.20939861871415,
    "monoisotopicMass": 165.09155465812998,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Dnp",
    "name": "2,4-Dinitrophenyl",
    "mf": "C6H3N2O4",
    "kind": "",
    "ocl": {
      "value": "dkmB`bWatpVRd^VS{HhheEUFfBAbX@@",
      "coordinates": "!B_c~H_]]}b@I~Owx_`BH_]]}_c~H_]]}"
    },
    "mass": 167.09926376274353,
    "monoisotopicMass": 167.00928158383,
    "unsaturation": 11,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 3
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 4
    }]
  }, {
    "symbol": "Et",
    "name": "Ethyl",
    "mf": "C2H5",
    "kind": "",
    "ocl": {
      "value": "eMBAYRZ@",
      "coordinates": "!B@Fp@Xp"
    },
    "mass": 29.061175563749384,
    "monoisotopicMass": 29.03912516115,
    "unsaturation": -1,
    "elements": [{
      "symbol": "C",
      "number": 2
    }, {
      "symbol": "H",
      "number": 5
    }]
  }, {
    "symbol": "Fmoc",
    "name": "Fluorenylmethoxycarbonyl",
    "mf": "C15H11O2",
    "kind": "",
    "ocl": {
      "value": "fde@b@DX@liMkLrjxeVCzLuT@@@P@@@",
      "coordinates": "!BbOq~@Ha}bOrH_]ARcm}Tv~i`pAeKv|@fpB[j[~iozfAKvp"
    },
    "mass": 223.24719659427882,
    "monoisotopicMass": 223.07590459367,
    "unsaturation": 19,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "For",
    "name": "Formyl",
    "mf": "CHO",
    "kind": "",
    "ocl": {
      "value": "eMJDVTfP@",
      "coordinates": "!B@Fp@Xp"
    },
    "mass": 29.018081575109303,
    "monoisotopicMass": 29.0027396518,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 1
    }, {
      "symbol": "H",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Gln",
    "name": "Glutamine diradical",
    "mf": "C5H8N2O2",
    "kind": "aa",
    "oneLetter": "Q",
    "alternativeOneLetter": "ξ",
    "ocl": {
      "value": "dmUDPBUICqYqR[evfjihr@@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHGx@bGt"
    },
    "mass": 128.12942178765059,
    "monoisotopicMass": 128.05857750584,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 8
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Glnp",
    "name": "Glutamine triradical",
    "mf": "C5H7N2O2",
    "kind": "",
    "ocl": {
      "value": "dcuDpH{MAYeqWqRVuejZjiad@",
      "coordinates": "!BbGvHGx@bGvH@ha}_c~HM]}_`BH_P"
    },
    "mass": 127.12148103359483,
    "monoisotopicMass": 127.05075247361,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Glp",
    "name": "Pyroglutamine",
    "mf": "C5H5NO2",
    "kind": "",
    "ocl": {
      "value": "deVDPBRP|V\\TfygxYjjZL`@",
      "coordinates": "!Bb@I~@Ha}tEJNwr[@UMo@FXBN"
    },
    "mass": 111.09889631403748,
    "monoisotopicMass": 111.03202840472,
    "unsaturation": 6,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Glu",
    "name": "Glutamic acid diradical",
    "mf": "C5H7NO3",
    "kind": "aa",
    "oneLetter": "E",
    "alternativeOneLetter": "ε",
    "ocl": {
      "value": "dmVLPBRUCqYqR[evfjihr@@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHGx@bGt"
    },
    "mass": 129.11418274646732,
    "monoisotopicMass": 129.04259308875,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Glup",
    "name": "Glutamic acid triradical",
    "mf": "C5H6NO3",
    "kind": "",
    "ocl": {
      "value": "dcvLpNcM@IeqWqRVuejZjiad@",
      "coordinates": "!BbGvHGx@bGvH@ha}_c~HM]}_`BH_P"
    },
    "mass": 128.10624199241153,
    "monoisotopicMass": 128.03476805652002,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Gly",
    "name": "Glycine diradical",
    "mf": "C2H3NO",
    "kind": "aa",
    "oneLetter": "G",
    "alternativeOneLetter": "γ",
    "ocl": {
      "value": "gGYDBaxuqR[Yj@@",
      "coordinates": "!BbOq~@Ha}bOrH_P"
    },
    "mass": 57.051402191401905,
    "monoisotopicMass": 57.021463720689994,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 2
    }, {
      "symbol": "H",
      "number": 3
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Hci",
    "name": "Homocitrulline diradical",
    "mf": "C7H13N3O2",
    "kind": "",
    "ocl": {
      "value": "dgoDPBVtLOEgEInWUZZjjfcH@",
      "coordinates": "!BbGu~Ox`B_`BH_Xc|bOrH_X`BbGvHGx@bGt"
    },
    "mass": 171.19730056284578,
    "monoisotopicMass": 171.10077667142,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Hcip",
    "name": "Homocitrulline triradical",
    "mf": "C7H12N3O2",
    "kind": "",
    "ocl": {
      "value": "do_DpHI\\\\EdwFEI[UVVijjjfIP@",
      "coordinates": "!BbOrH_Wxb@JH_Xc|bGvHHa}_c~H@m]}_`BH_P"
    },
    "mass": 170.18935980879002,
    "monoisotopicMass": 170.09295163918998,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "His",
    "name": "Histidine diradical",
    "mf": "C6H7N3O",
    "kind": "aa",
    "oneLetter": "H",
    "alternativeOneLetter": "ζ",
    "ocl": {
      "value": "dcOHPBGTCqYqR[eyUvZjejL`@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGwPTh{_UMo@FP"
    },
    "mass": 137.13951521745759,
    "monoisotopicMass": 137.05891185847,
    "unsaturation": 8,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Hisp",
    "name": "Histidine triradical",
    "mf": "C6H6N3O",
    "kind": "",
    "ocl": {
      "value": "dkoHpHHSAYUqwqRY]YXjjVjihy@@",
      "coordinates": "!BTmA}bL@fUHRN`H`BbGu~Ox`Buwu~@Ha}"
    },
    "mass": 136.13157446340182,
    "monoisotopicMass": 136.05108682624,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Hser",
    "name": "Homoserine diradical",
    "mf": "C4H7NO2",
    "kind": "",
    "ocl": {
      "value": "diFDPBPP|V\\Tfy^Zjhr@@",
      "coordinates": "!BbGu~Ox`B_`BH_X`Bb@JH_P"
    },
    "mass": 101.10404192541378,
    "monoisotopicMass": 101.04767846918,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Hserp",
    "name": "Homoserine triradical",
    "mf": "C4H6NO2",
    "kind": "",
    "ocl": {
      "value": "defDpJbPV^\\Q|TeVVjji`d@",
      "coordinates": "!Bb@JH_X`BbGu~Oxc|uwu~@Ha}"
    },
    "mass": 100.09610117135801,
    "monoisotopicMass": 100.03985343695001,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Hyp",
    "name": "Hydroxyproline diradical",
    "mf": "C5H7NO2",
    "kind": "",
    "ocl": {
      "value": "deVDPBRP|V\\\\bfbbOCMUUIdE@@",
      "coordinates": "!Bb@I~@Ha}tEJNwr[@UMo@FUJO"
    },
    "mass": 113.11477782214904,
    "monoisotopicMass": 113.04767846918,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Hypp",
    "name": "Hydroxyproline triradical",
    "mf": "C5H6NO2",
    "kind": "",
    "ocl": {
      "value": "dmvDpJaPB^\\Y|TeeWjZjjidRL`@",
      "coordinates": "!BBOpH_UARcc}TNtBY@HyRSpCQDr\\"
    },
    "mass": 112.10683706809326,
    "monoisotopicMass": 112.03985343695001,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Ile",
    "name": "Isoleucine diradical",
    "mf": "C6H11NO",
    "kind": "aa",
    "oneLetter": "I",
    "alternativeOneLetter": "ι",
    "ocl": {
      "value": "defHPBPOEgEInVyjjdrT`@",
      "coordinates": "!BbGu~Oxc|_`BH_Xc|b@I~Oxa}"
    },
    "mass": 113.15787181078912,
    "monoisotopicMass": 113.08406397853,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Ivdde",
    "name": "1-[4,4-dimethyl-2,6-dioxocyclohexylidene)-3-methylbutyl",
    "mf": "C13H19O2",
    "kind": "",
    "ocl": {
      "value": "f`a@b@NR@lyEEDhhigEVfjYjj`@@",
      "coordinates": "!BbOq~@Ha}urHGxuwu~@Ha}_`CW_Xa}bOq}b@JH"
    },
    "mass": 207.28925083325453,
    "monoisotopicMass": 207.13850485151,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 19
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Leu",
    "name": "Leucine diradical",
    "mf": "C6H11NO",
    "kind": "aa",
    "oneLetter": "L",
    "alternativeOneLetter": "λ",
    "ocl": {
      "value": "defHPBPOEgEInWijjhr@@",
      "coordinates": "!BbGu~Ox`B_`BH_X`Bb@I~@Ha}"
    },
    "mass": 113.15787181078912,
    "monoisotopicMass": 113.08406397853,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Lys",
    "name": "Lysine diradical",
    "mf": "C6H12N2O",
    "kind": "aa",
    "oneLetter": "K",
    "alternativeOneLetter": "κ",
    "ocl": {
      "value": "dmUHPBU@|V\\Tfy]YjjjL`@",
      "coordinates": "!BbGu~Ox`B_`BHoX`Bb@JH_X`BbKt"
    },
    "mass": 128.17251577629068,
    "monoisotopicMass": 128.09496301519,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Lysp",
    "name": "Lysine triradical",
    "mf": "C6H11N2O",
    "kind": "",
    "ocl": {
      "value": "dcuHpH{PVY\\U|TeUYZjjjXY@@",
      "coordinates": "!Bb@JH_X`BbGvH@ha}_c~H@m]}_`BH_P"
    },
    "mass": 127.16457502223491,
    "monoisotopicMass": 127.08713798295999,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Mbh",
    "name": "4,4'-Dimethoxybenzhydryl",
    "mf": "C15H15O2",
    "kind": "",
    "ocl": {
      "value": "fdy@b@G^@liLsJkzlcZmT@@@UP@@@",
      "coordinates": "!BbGvHGx_`BH_Xa}uwvHHc|_c}~Oxa}uwvHGxbGwW_P"
    },
    "mass": 227.27895961050194,
    "monoisotopicMass": 227.10720472258998,
    "unsaturation": 15,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Me",
    "name": "Methyl",
    "mf": "CH3",
    "kind": "",
    "ocl": {
      "value": "eFBAYc@@",
      "coordinates": "!B@FL"
    },
    "mass": 15.03455815890258,
    "monoisotopicMass": 15.02347509669,
    "unsaturation": -1,
    "elements": [{
      "symbol": "C",
      "number": 1
    }, {
      "symbol": "H",
      "number": 3
    }]
  }, {
    "symbol": "Mebzl",
    "name": "4-Methylbenzyl",
    "mf": "C8H9",
    "kind": "",
    "ocl": {
      "value": "did@`@VTee]nh@H@@",
      "coordinates": "!B|Gsp__A|_gp_C}_gp_P"
    },
    "mass": 105.15735396038399,
    "monoisotopicMass": 105.07042529007,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 9
    }]
  }, {
    "symbol": "Meobzl",
    "name": "4-Methoxybenzyl",
    "mf": "C8H9O",
    "kind": "",
    "ocl": {
      "value": "deTH`AAYRVUunh@J@@",
      "coordinates": "!B|Gsp__A|_gp_A}_gp_Wy"
    },
    "mass": 121.15675888470227,
    "monoisotopicMass": 121.06533990964,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Met",
    "name": "Methionine diradical",
    "mf": "C5H9NOS",
    "kind": "aa",
    "oneLetter": "M",
    "alternativeOneLetter": "μ",
    "ocl": {
      "value": "defHpBPOEgDPaInWYjjhr@@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}"
    },
    "mass": 131.19604181206938,
    "monoisotopicMass": 131.04048508847,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mmt",
    "name": "4-Methoxytrityl",
    "mf": "C20H17O",
    "kind": "",
    "ocl": {
      "value": "ffcAB@B`V\\bdTTTRRRVvIhnRGMT@@@@AP@@@",
      "coordinates": "!BbKvHM^}_c}~@Hb}dXWHb}j|nHHc|AqOWoWxJV^Ho]\\BuwvHHb}"
    },
    "mass": 273.3491156779715,
    "monoisotopicMass": 273.12794016748,
    "unsaturation": 23,
    "elements": [{
      "symbol": "C",
      "number": 20
    }, {
      "symbol": "H",
      "number": 17
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Mtc",
    "name": "2,2,5,7,8-pentamethylchroman-6-sulphonyl",
    "mf": "C14H19O3S",
    "kind": "",
    "ocl": {
      "value": "fleAa@DX\\AY`DYEHXhhilmiKW`rpDQUUD@@",
      "coordinates": "!BbGtBbGwWbGvHGxbGu~@Ha}uwu~Ox`B_c~H_Xa}b@H@_osW"
    },
    "mass": 267.36417906043516,
    "monoisotopicMass": 267.10549064548,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 14
    }, {
      "symbol": "H",
      "number": 19
    }, {
      "symbol": "O",
      "number": 3
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mtr",
    "name": "4-Methoxy-2,3,6-trimethylbenzenesulphonyl",
    "mf": "C10H13O3S",
    "kind": "",
    "ocl": {
      "value": "do|LPDrpVXBLbdLTTTngYXBHj@@",
      "coordinates": "!BbOq}b@KWb@I~@Ha}bOsWHc|_c~H_Wx@b@JH_P"
    },
    "mass": 213.27359094915948,
    "monoisotopicMass": 213.05854045209998,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "O",
      "number": 3
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mts",
    "name": "Mesitylene-2-sulphonyl",
    "mf": "C9H11O2S",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 183.24756861999438,
    "monoisotopicMass": 183.04797576807,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "O",
      "number": 2
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mtt",
    "name": "4-Methyltrityl",
    "mf": "C20H17",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 257.3497107536532,
    "monoisotopicMass": 257.13302554791,
    "unsaturation": 23,
    "elements": [{
      "symbol": "C",
      "number": 20
    }, {
      "symbol": "H",
      "number": 17
    }]
  }, {
    "symbol": "Nle",
    "name": "Norleucine diradical",
    "mf": "C6H11NO",
    "kind": "",
    "ocl": {
      "value": "defHPBPOEgEInWYjjhr@@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}"
    },
    "mass": 113.15787181078912,
    "monoisotopicMass": 113.08406397853,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Npys",
    "name": "3-Nitro-2-pyridinesulphenyl",
    "mf": "C5H3N2O2S",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 155.1545054234988,
    "monoisotopicMass": 154.99152351908998,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 3
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 2
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Nva",
    "name": "Norvaline diradical",
    "mf": "C5H9NO",
    "kind": "",
    "ocl": {
      "value": "diFHPBPOEgEInWfjjL`@",
      "coordinates": "!BbGu~Ox`B_`BH_X`Bb@JH_P"
    },
    "mass": 99.13125440594231,
    "monoisotopicMass": 99.06841391407,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Odmab",
    "name": "Odmab",
    "mf": "C20H26NO3",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 328.4260955245558,
    "monoisotopicMass": 328.19126870111995,
    "unsaturation": 15,
    "elements": [{
      "symbol": "C",
      "number": 20
    }, {
      "symbol": "H",
      "number": 26
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Orn",
    "name": "Ornithine diradical",
    "mf": "C5H10N2O",
    "kind": "",
    "ocl": {
      "value": "deeHPBe@|V\\Tfy]fjjcH@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvHHa}"
    },
    "mass": 114.14589837144388,
    "monoisotopicMass": 114.07931295072999,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 10
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Ornp",
    "name": "Ornithine triradical",
    "mf": "C5H9N2O",
    "kind": "",
    "ocl": {
      "value": "dmUHpHYPBQ\\Y|TeUejjjfJP@",
      "coordinates": "!BbGvHHa}b@JH_Wxb@KW_Wx@bGt"
    },
    "mass": 113.13795761738811,
    "monoisotopicMass": 113.0714879185,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Pbf",
    "name": "2,2,4,6,7-pentamethyldihydrobenzofurane-5-sulfonyl",
    "mf": "C13H17O3S",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 253.33756165558833,
    "monoisotopicMass": 253.08984058101998,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 17
    }, {
      "symbol": "O",
      "number": 3
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Pen",
    "name": "Penicillamine diradical",
    "mf": "C5H9NOS",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 131.19604181206938,
    "monoisotopicMass": 131.04048508847,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Penp",
    "name": "Penicillamine triradical",
    "mf": "C5H8NOS",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 130.1881010580136,
    "monoisotopicMass": 130.03266005624,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 8
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Ph",
    "name": "Phenyl",
    "mf": "C6H5",
    "kind": "",
    "ocl": {
      "value": "gOpH@liLkW@@@@",
      "coordinates": "!B|Owp_Gy|OwpWy"
    },
    "mass": 77.10411915069038,
    "monoisotopicMass": 77.03912516115,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 5
    }]
  }, {
    "symbol": "Phe",
    "name": "Phenylalanine diradical",
    "mf": "C9H9NO",
    "kind": "aa",
    "oneLetter": "F",
    "alternativeOneLetter": "φ",
    "ocl": {
      "value": "dknHPBPOEgEInWe]NZj@@cH@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGvH@gxbGvH_Wx"
    },
    "mass": 147.1741979928833,
    "monoisotopicMass": 147.06841391407002,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Phepcl",
    "name": "4-Chlorophenylalanine diradical",
    "mf": "C9H8ClNO",
    "kind": "",
    "ocl": {
      "value": "dg^HpBPOEgFxaInWe_Sfj`@bL`@",
      "coordinates": "!BbOq~@Ha}_c~H@m]}bGvH@gxbGvH_WxbGt"
    },
    "mass": 181.6191948214355,
    "monoisotopicMass": 181.02944156384,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 8
    }, {
      "symbol": "Cl",
      "number": 1
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Phg",
    "name": "Phenylglycine",
    "mf": "C8H7NO",
    "kind": "",
    "ocl": {
      "value": "dcNHPBPOEgEInVuWYj`@Hr@@",
      "coordinates": "!BbOq~@Ha}b@I~Oxa}bGwW_Wx_cW_P"
    },
    "mass": 133.1475805880365,
    "monoisotopicMass": 133.05276384961002,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Pmc",
    "name": "2,2,5,7,8-Pentamethylchroman-6-sulphonyl",
    "mf": "C14H19O3S",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 267.36417906043516,
    "monoisotopicMass": 267.10549064548,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 14
    }, {
      "symbol": "H",
      "number": 19
    }, {
      "symbol": "O",
      "number": 3
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Pro",
    "name": "Proline diradical",
    "mf": "C5H7NO",
    "kind": "aa",
    "oneLetter": "P",
    "alternativeOneLetter": "π",
    "ocl": {
      "value": "difHPBPOEgEInYxYjjhr@@",
      "coordinates": "!Bb@I~@Ha}tEJNwr[@UMo@FP"
    },
    "mass": 97.11537289783075,
    "monoisotopicMass": 97.05276384961,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Pyr",
    "name": "Pyroglutamine",
    "mf": "C5H5NO2",
    "kind": "",
    "ocl": {
      "value": "deVDPBRP|V\\TfygxYjjZL`@",
      "coordinates": "!Bb@I~@Ha}tEJNwr[@UMo@FXBN"
    },
    "mass": 111.09889631403748,
    "monoisotopicMass": 111.03202840472,
    "unsaturation": 6,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Sar",
    "name": "Sarcosine diradical",
    "mf": "C3H5NO",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 71.07801959624871,
    "monoisotopicMass": 71.03711378515,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 3
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Ser",
    "name": "Serine diradical",
    "mf": "C3H5NO2",
    "kind": "aa",
    "oneLetter": "S",
    "alternativeOneLetter": "σ",
    "ocl": {
      "value": "dazDPBS`|V\\TfyYjjL`@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}bGt"
    },
    "mass": 87.07742452056698,
    "monoisotopicMass": 87.03202840472,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 3
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Serp",
    "name": "Serine triradical",
    "mf": "C3H4NO2",
    "kind": "",
    "ocl": {
      "value": "diFDpB`PBV\\^|TeYZjjXq@@",
      "coordinates": "!BbGvHHa}_c~HM]}_`BH_P"
    },
    "mass": 86.06948376651121,
    "monoisotopicMass": 86.02420337249,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 3
    }, {
      "symbol": "H",
      "number": 4
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Sta",
    "name": "Statine diradical",
    "mf": "C8H15NO2",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 157.210511544801,
    "monoisotopicMass": 157.11027872702002,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Stap",
    "name": "Statine triradical",
    "mf": "C8H14NO2",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 156.2025707907452,
    "monoisotopicMass": 156.10245369479,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Tacm",
    "name": "Trimethylacetamidomethyl",
    "mf": "C6H12NO",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 114.16581256484488,
    "monoisotopicMass": 114.09188901076,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Tbdms",
    "name": "t-Butyldimethylsilyl",
    "mf": "C6H15Si",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 115.2690253969541,
    "monoisotopicMass": 115.09430201810001,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "Si",
      "number": 1
    }]
  }, {
    "symbol": "Tbu",
    "name": "t-Butyl",
    "mf": "C4H9",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 57.114410373442986,
    "monoisotopicMass": 57.07042529007,
    "unsaturation": -1,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 9
    }]
  }, {
    "symbol": "Tbuo",
    "name": "t-Butoxy",
    "mf": "C4H9O",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 73.11381529776126,
    "monoisotopicMass": 73.06533990964,
    "unsaturation": -1,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Tbuthio",
    "name": "t-Butylthio",
    "mf": "C4H9S",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 89.17919777957005,
    "monoisotopicMass": 89.04249646446999,
    "unsaturation": -1,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Tfa",
    "name": "Trifluoroacetyl",
    "mf": "C2F3O",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 97.01608620597878,
    "monoisotopicMass": 96.99012410776,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 2
    }, {
      "symbol": "F",
      "number": 3
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Thr",
    "name": "Threonine diradical",
    "mf": "C4H7NO2",
    "kind": "aa",
    "oneLetter": "T",
    "alternativeOneLetter": "τ",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 101.10404192541378,
    "monoisotopicMass": 101.04767846918,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Thrp",
    "name": "Threonine triradical",
    "mf": "C4H6NO2",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 100.09610117135801,
    "monoisotopicMass": 100.03985343695001,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 4
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Tfsi",
    "name": "(Bis)(trifluoromethanesulfonyl)imide",
    "mf": "C2F6NO4S2",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 280.1457884908235,
    "monoisotopicMass": 279.91729380789,
    "unsaturation": -1,
    "elements": [{
      "symbol": "C",
      "number": 2
    }, {
      "symbol": "F",
      "number": 6
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 4
    }, {
      "symbol": "S",
      "number": 2
    }]
  }, {
    "symbol": "Tips",
    "name": "Triisopropylsilyl",
    "mf": "C9H21Si",
    "kind": "",
    "ocl": {
      "value": "dmT@P@VX\\DffYjjjh@@",
      "coordinates": "!B_a@gHb\\]FBIuWxP^zi~KwxPFAt"
    },
    "mass": 157.34887761149452,
    "monoisotopicMass": 157.14125221148,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 21
    }, {
      "symbol": "Si",
      "number": 1
    }]
  }, {
    "symbol": "Tms",
    "name": "Trimethylsilyl",
    "mf": "C3H9Si",
    "kind": "",
    "ocl": {
      "value": "gJPD@lqpRZj`@",
      "coordinates": "!BbOq~@GxbGt"
    },
    "mass": 73.1891731824137,
    "monoisotopicMass": 73.04735182472,
    "unsaturation": 1,
    "elements": [{
      "symbol": "C",
      "number": 3
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "Si",
      "number": 1
    }]
  }, {
    "symbol": "Tos",
    "name": "Tosyl",
    "mf": "C7H7O2S",
    "kind": "",
    "ocl": {
      "value": "dmtDPDpEf@cHiCDeafV@B@@",
      "coordinates": "!B|Ou||Ovw|Gwp_Gy|GwpWy|Gt"
    },
    "mass": 155.1943338103008,
    "monoisotopicMass": 155.01667563914998,
    "unsaturation": 7,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "O",
      "number": 2
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Trp",
    "name": "Tryptophan diradical",
    "mf": "C11H10N2O",
    "kind": "aa",
    "oneLetter": "W",
    "alternativeOneLetter": "ω",
    "ocl": {
      "value": "f`qQA@BFPCqXxiMr|rnhsoSUTa@QCD@@",
      "coordinates": "!BbOq~@Ha}_c~H@m]}bGwPTh{_UMojXL@YpB[@Ini`"
    },
    "mass": 186.21031375185538,
    "monoisotopicMass": 186.07931295073,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 10
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Trpp",
    "name": "Tryptophan triradical",
    "mf": "C11H9N2O",
    "kind": "",
    "ocl": {
      "value": "fhiQC@HFB@I\\x~|TfYU_ebLDjhDHjibFd@",
      "coordinates": "!BTmA}bL@fUHR_Ihz@iVBeXHc|grZH_WxbOsW_Wx@bGt"
    },
    "mass": 185.20237299779959,
    "monoisotopicMass": 185.07148791850003,
    "unsaturation": 15,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Trt",
    "name": "Trityl",
    "mf": "C19H15",
    "kind": "",
    "ocl": {
      "value": "fbm@B@@KJSSLrjkyhnRGMT@@@@@@@@",
      "coordinates": "!BrHI~PGy_rMvW@l`BQCvWw\\bBAg}~PGy@]i}~W|c]cNwH`i_]_e|"
    },
    "mass": 243.32309334880637,
    "monoisotopicMass": 243.11737548345,
    "unsaturation": 23,
    "elements": [{
      "symbol": "C",
      "number": 19
    }, {
      "symbol": "H",
      "number": 15
    }]
  }, {
    "symbol": "Tyr",
    "name": "Tyrosine diradical",
    "mf": "C9H9NO2",
    "kind": "aa",
    "oneLetter": "Y",
    "alternativeOneLetter": "ψ",
    "ocl": {
      "value": "dg^DPBRp|V\\Tfy^U}NZj@BHr@@",
      "coordinates": "!BbOq~@Ha}_c~H@m]}bGvH@gxbGvH_WxbGt"
    },
    "mass": 163.1736029172016,
    "monoisotopicMass": 163.06332853364,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Tyrp",
    "name": "Tyrosine triradical",
    "mf": "C9H8NO2",
    "kind": "",
    "ocl": {
      "value": "do~DpEapBS\\[|Tee]YYnh@JjdbT@",
      "coordinates": "!B_`BHGx@bGvH@h`BbKvH@ha}_c~H@m]}_`BHoP"
    },
    "mass": 162.16566216314578,
    "monoisotopicMass": 162.05550350141,
    "unsaturation": 11,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 8
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Val",
    "name": "Valine",
    "mf": "C5H9NO",
    "kind": "aa",
    "oneLetter": "V",
    "alternativeOneLetter": "ν",
    "ocl": {
      "value": "diFHPBPOEgEInVfjjL`@",
      "coordinates": "!Bb@I~@Ha}_c~H@m]}_`BH_P"
    },
    "mass": 99.13125440594231,
    "monoisotopicMass": 99.06841391407,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Valoh",
    "name": "beta-Hydroxyvaline diradical",
    "mf": "C5H9NO2",
    "kind": "",
    "ocl": {
      "value": "defDPBS`|V\\TfyZfjjcH@",
      "coordinates": "!Bb@I~@Ha}b@I~Oxa}Owy~OpA~"
    },
    "mass": 115.13065933026058,
    "monoisotopicMass": 115.06332853364,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Valohp",
    "name": "beta-Hydroxyvaline triradical",
    "mf": "C5H8NO2",
    "kind": "",
    "ocl": {
      "value": "dmVDpFaPBQ\\Y|\\bTbaTjjjXq@@",
      "coordinates": "!BbGvHHa}_Xc|bGxb@KW_Wx@bGt"
    },
    "mass": 114.1227185762048,
    "monoisotopicMass": 114.05550350141002,
    "unsaturation": 3,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 8
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Xan",
    "name": "Xanthyl",
    "mf": "C13H9O",
    "kind": "",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 181.21043836837848,
    "monoisotopicMass": 181.06533990964002,
    "unsaturation": 17,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Xle",
    "name": "Leucine or Isoleucine diradical",
    "mf": "C6H11NO",
    "kind": "aa",
    "oneLetter": "J",
    "mass": 113.15787181078912,
    "monoisotopicMass": 113.08406397853,
    "unsaturation": 2,
    "elements": [{
      "symbol": "C",
      "number": 6
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 1
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Z",
    "name": "Benzyloxycarbonyl",
    "mf": "C8H7O2",
    "kind": "",
    "ocl": {
      "value": "dmtD`DpEeImYVUfh@@@@",
      "coordinates": "!Bb@I~@Ha}b@JH_Xc|_c~H_Xa}_c|"
    },
    "mass": 135.14028230090898,
    "monoisotopicMass": 135.04460446475,
    "unsaturation": 9,
    "elements": [{
      "symbol": "C",
      "number": 8
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Damp",
    "name": "Desoxyadenosine monophosphate diradical",
    "mf": "C10H12N5O5P",
    "kind": "DNAp",
    "oneLetter": "A",
    "alternativeOneLetter": "α",
    "ocl": {
      "value": "fnsiS@IASUlJB]xGbkplxyDhhldhiEEUeSdTekUUUULBATXPlKd@@",
      "coordinates": "!Bqc}{JxyO|XoSWC}W]poGQ\\Ou}]rmx\\Ou}]{qpza|qb}MJwlk^sFO|X"
    },
    "mass": 313.2069506932622,
    "monoisotopicMass": 313.05760550518,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 5
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dcmp",
    "name": "Desoxycytidine monophosphate diradical",
    "mf": "C9H12N3O6P",
    "kind": "DNAp",
    "oneLetter": "C",
    "alternativeOneLetter": "ς",
    "ocl": {
      "value": "fjmps@IQKB`g^BCqUxV\\\\bTTVRTTbb^iqNZjjjifVkBEa\\`@",
      "coordinates": "!Bqc}{JxyO|XoSWA}_W]poGQ\\GuMKuMh\\Gu}]{qpSF]tWQTvatP"
    },
    "mass": 289.18221329795364,
    "monoisotopicMass": 289.04637211589,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dgmp",
    "name": "Desoxyguanosine monophosphate diradical",
    "mf": "C10H12N5O6P",
    "kind": "DNAp",
    "oneLetter": "G",
    "alternativeOneLetter": "γ",
    "ocl": {
      "value": "fakhs@IASUlJB]{hOEWaYqrIQQYIQRJJkQTyEIZuUUUSRtsUaBpnP@",
      "coordinates": "!Bqc}{JxyO|XoSWA}W]poGQ\\Gu}]rmx\\Ou}]{qpza|qb}MJwlk^sFza|q`"
    },
    "mass": 329.20635561758047,
    "monoisotopicMass": 329.05252012475,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dtmp",
    "name": "Desoxythymidine monophosphate diradical",
    "mf": "C10H13N2O7P",
    "kind": "DNAp",
    "oneLetter": "T",
    "alternativeOneLetter": "τ",
    "ocl": {
      "value": "ff}Qs@IQaPSoAjCqUxV\\\\bTTVRTTbbZUNIsUUUULsSVDKBy@@",
      "coordinates": "!Bqc}{JxyO|XoSWC}_W]poGQ\\GuMKuMh\\Gu}]{qpSF]tWQTvaSZGQ"
    },
    "mass": 304.1935916616171,
    "monoisotopicMass": 304.04603776326,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dump",
    "name": "Desoxyuridine monophosphate diradical",
    "mf": "C9H11N2O7P",
    "kind": "DNAp",
    "oneLetter": "U",
    "alternativeOneLetter": "υ",
    "ocl": {
      "value": "fjmQs@IQaPSoAJCqUxV\\\\bTTVRTTbb^iqNZjjjifYkBEa\\`@",
      "coordinates": "!Bqc}{JxyO|XoSWA}_W]poGQ\\GuMKuMh\\Gu}]{qpSF]tWQTvatP"
    },
    "mass": 290.1669742567703,
    "monoisotopicMass": 290.0303876988,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Drmp",
    "name": "Desoxyribose monophosphate diradical",
    "mf": "C5H7O5P",
    "kind": "DNAp",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 178.08005138207807,
    "monoisotopicMass": 178.00311032188,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "O",
      "number": 5
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dadp",
    "name": "Desoxyadenosine diphosphate diradical",
    "mf": "C10H13N5O8P2",
    "kind": "DNApp",
    "oneLetter": "A",
    "ocl": {
      "value": "fmwhH`IASM\\JBl{wQ`|U^F_AkbdlsjsSOoRtyEMYuUUUM@pSEQaBpnP@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGu}utnDM^HGwWzf~_Ih}M_`AKvto[_`@_`A~grZ_I`"
    },
    "mass": 393.1868682186928,
    "monoisotopicMass": 393.02393639454,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Dcdp",
    "name": "Desoxycytidine diphosphate diradical",
    "mf": "C9H13N3O9P2",
    "kind": "DNApp",
    "oneLetter": "C",
    "ocl": {
      "value": "fikqH`IQGB`kN|EoP^JoCOaUqrIQQYIQRJKGRJgDejjjjZYfZkBEa\\`@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFGx@Owx@_mQ"
    },
    "mass": 369.16213082338425,
    "monoisotopicMass": 369.01270300525005,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Dgdp",
    "name": "Desoxyguanosine diphosphate diradical",
    "mf": "C10H13N5O9P2",
    "kind": "DNApp",
    "oneLetter": "G",
    "ocl": {
      "value": "fcoiH`IASM\\JBl{wQ{Axj|L~CWEIYgUff_^fZ\\bflzjjjfiZifZlHVEr@@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGu}utnD@m^H@gwWzf~_Ih}M_`AKvto[_`@_`A~gr[j[y|f"
    },
    "mass": 409.186273143011,
    "monoisotopicMass": 409.01885101411,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Dtdp",
    "name": "Desoxythymidine diphosphate diradical",
    "mf": "C10H14N2O10P2",
    "kind": "DNApp",
    "oneLetter": "T",
    "ocl": {
      "value": "fe{Ph`IQaPUg^Ct\\p^JoCO`uqrIQQYIQRJKEJQTxdmUUUSSMTsVDKBy@@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^HMQbGuMcqLX@m^H@gwWKB__t]Q_`@SFALX_`@_`A~w}D"
    },
    "mass": 384.1735091870477,
    "monoisotopicMass": 384.01236865262,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Dudp",
    "name": "Desoxyuridine diphosphate diradical",
    "mf": "C9H12N2O10P2",
    "kind": "DNApp",
    "oneLetter": "U",
    "ocl": {
      "value": "fikPh`IQaPUg^Bwhp^JoCOaUqrIQQYIQRJKGRJgDejjjjZYjYkBEa\\`@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFGx@Owx@_mQ"
    },
    "mass": 370.1468917822009,
    "monoisotopicMass": 369.99671858816,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Datp",
    "name": "Desoxyadenosine triphosphate diradical",
    "mf": "C10H14N5O11P3",
    "kind": "DNAppp",
    "oneLetter": "A",
    "ocl": {
      "value": "eohZMJ@I@diehJAKGOFnakg`OESpr|Mo@yqrIQQYIQRJKYZQKVRcbIJjZjjjihFAhjZcAAXKb@@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGu}utnDM^H@gwWzf~_Ih}M_`AKvto[@hcW@`A~grZ_Igx@_`@@_c}~"
    },
    "mass": 473.16678574412344,
    "monoisotopicMass": 472.9902672839,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Dctp",
    "name": "Desoxycytidine triphosphate diradical",
    "mf": "C9H14N3O12P3",
    "kind": "DNAppp",
    "oneLetter": "C",
    "ocl": {
      "value": "fkopZ`IQGB`kN|Fk^{NCqUxY|I~BwGHeEEdeEHhl]HlYJ\\RVjjjiifVjfkBEa\\`@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFOrHupH@_mQ_`A~@@A~Owx"
    },
    "mass": 449.14204834881485,
    "monoisotopicMass": 448.97903389461004,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 12
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Dgtp",
    "name": "Desoxyguanosine triphosphate diradical",
    "mf": "C10H14N5O12P3",
    "kind": "DNAppp",
    "oneLetter": "G",
    "ocl": {
      "value": "e`TZCJ@I@diehJAKGOFnamgo`OESpr|CoByqrIQQYIQRJKYZQQYrT\\QIUSUUUUMRuMLtuVBBpWD@@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGu}utnD@m^H@gwWzf~_Ih}M_`AKvto[@hcW@`A~gr[j[y|f_`A~@@A~Owx"
    },
    "mass": 489.16619066844174,
    "monoisotopicMass": 488.98518190347005,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 12
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Dttp",
    "name": "Desoxythymidine triphosphate diradical",
    "mf": "C10H15N2O13P3",
    "kind": "DNAppp",
    "oneLetter": "T",
    "ocl": {
      "value": "fgQZ`IQaPUg^BwhygnCqUxY|E~FwGHeEEdeEHhlTiDSISbRuUUUMLuMMMVDKBy@@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFALXHcW@`A~w}E~@Gx@@Gx_`"
    },
    "mass": 464.15342671247834,
    "monoisotopicMass": 463.97869954198,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 13
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Dutp",
    "name": "Desoxyuridine triphosphate diradical",
    "mf": "C9H13N2O13P3",
    "kind": "DNAppp",
    "oneLetter": "U",
    "ocl": {
      "value": "fkoQZ`IQaPUg^CUoQ{NCqUxY|I~BwGHeEEdeEHhl]HlYJ\\RVjjjiiffffkBEa\\`@",
      "coordinates": "!BIi[Rx{_grZOSXa}_]^H@mQbGuMcqLX@m^H@gwWKB__t]Q_`@SFOrHupH@_mQ_`A~@@A~Owx"
    },
    "mass": 450.1268093076315,
    "monoisotopicMass": 449.96304947752,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 13
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Dade",
    "name": "Desoxyadenosine diradical",
    "mf": "C10H11N5O2",
    "kind": "DNA",
    "oneLetter": "A",
    "ocl": {
      "value": "fluha@IF]ELJ@|QNJRsN|rntyYpXuUUTBATXPlKd@@",
      "coordinates": "!B\\KqpQARcg|T^|X@@Id`zeHo@Ie}]vaLcg|T^qAMDDvN_xy"
    },
    "mass": 233.22703316783156,
    "monoisotopicMass": 233.09127461582,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 2
    }]
  }, {
    "symbol": "Dcyt",
    "name": "Desoxycytidine diradical",
    "mf": "C9H11N3O3",
    "kind": "DNA",
    "oneLetter": "C",
    "ocl": {
      "value": "fhiqa@IVCBa`^HgEIYg^Y~gG^jjjiejpaXWH@",
      "coordinates": "!BBOpH_UARcc}TN|Y@PIe`zeIO@MDSIrpXTd}RSqLgTd|"
    },
    "mass": 209.202295772523,
    "monoisotopicMass": 209.08004122653,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Dgua",
    "name": "Desoxyguanosine diradical",
    "mf": "C10H11N5O3",
    "kind": "DNA",
    "oneLetter": "G",
    "ocl": {
      "value": "fbmia@IF]ELJYAxb\\Tef]ye^Z\\lxLZjjjeZfkBEa\\`@",
      "coordinates": "!B\\KqpQARcg|T^|X@@Id`zeHo@Ie}]vaLcg|T^qAMDDvN_vaLcg|"
    },
    "mass": 249.22643809214986,
    "monoisotopicMass": 249.08618923539,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Dthy",
    "name": "Desoxythymidine diradical",
    "mf": "C10H12N2O4",
    "kind": "DNA",
    "oneLetter": "T",
    "ocl": {
      "value": "fdyPQ@IVaPtP^HgEIYg^YuiqwjjjjYikBEa\\`@",
      "coordinates": "!BBOpH_UARcc}TN|Y@PIe`zeIO@MDSIrpXTd}RSqLgDr]RSp"
    },
    "mass": 224.2136741361865,
    "monoisotopicMass": 224.07970687390002,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 4
    }]
  }, {
    "symbol": "Dura",
    "name": "Desoxyuridine diradical",
    "mf": "C9H10N2O4",
    "kind": "DNA",
    "oneLetter": "U",
    "ocl": {
      "value": "fhiPQ@IVaPpP^HgEIYg^Y~gG^jjjifZpaXWH@",
      "coordinates": "!BBOpH_UARcc}TN|Y@PIe`zeIO@MDSIrpXTd}RSqLgTd|"
    },
    "mass": 210.1870567313397,
    "monoisotopicMass": 210.06405680944,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 10
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 4
    }]
  }, {
    "symbol": "Amp",
    "name": "Adenosine monophosphate diradical",
    "mf": "C10H12N5O6P",
    "kind": "RNAp",
    "oneLetter": "A",
    "alternativeOneLetter": "α",
    "ocl": {
      "value": "fakhs@INBwlJ\\TgHOFwaEqrIQQSYQJIRIMLyxMVuUUUPLpEPQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@@"
    },
    "mass": 329.20635561758047,
    "monoisotopicMass": 329.05252012475,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Cmp",
    "name": "Cytidine monophosphate diradical",
    "mf": "C9H12N3O7P",
    "kind": "RNAp",
    "oneLetter": "C",
    "alternativeOneLetter": "ς",
    "ocl": {
      "value": "ff}qs@I^kBgENSdGc[pbxyDhhilheDiLv\\BVjjjjYfZbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
    },
    "mass": 305.1816182222719,
    "monoisotopicMass": 305.04128673546,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Gmp",
    "name": "Guanosine monophosphate diradical",
    "mf": "C10H12N5O7P",
    "kind": "RNAp",
    "oneLetter": "G",
    "alternativeOneLetter": "γ",
    "ocl": {
      "value": "fi{is@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\SN^CUmUUUUKMSMQDSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtP@gD}D@"
    },
    "mass": 345.20576054189877,
    "monoisotopicMass": 345.04743474432,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Tmp",
    "name": "Thymidine monophosphate diradical",
    "mf": "C10H13N2O8P",
    "kind": "RNAp",
    "oneLetter": "T",
    "alternativeOneLetter": "τ",
    "ocl": {
      "value": "fncPK@I^aSbgIrtGc[pbxyDhhilheDiLjs`RuUUUSLuMDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
    },
    "mass": 320.1929965859354,
    "monoisotopicMass": 320.04095238282997,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ump",
    "name": "Uridine monophosphate diradical",
    "mf": "C9H11N2O8P",
    "kind": "RNAp",
    "oneLetter": "U",
    "alternativeOneLetter": "υ",
    "ocl": {
      "value": "ff}PK@I^aSbgIsTGc[pbxyDhhilheDiLv\\BVjjjjYffbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
    },
    "mass": 306.1663791810886,
    "monoisotopicMass": 306.02530231837,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Rmp",
    "name": "Ribose monophosphate diradical",
    "mf": "C5H7O6P",
    "kind": "RNAp",
    "ocl": {
      "value": "d@",
      "coordinates": ""
    },
    "mass": 194.07945630639637,
    "monoisotopicMass": 193.99802494145,
    "unsaturation": 4,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 7
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Adp",
    "name": "Adenosine diphosphate diradical",
    "mf": "C10H13N5O9P2",
    "kind": "RNApp",
    "oneLetter": "A",
    "ocl": {
      "value": "fcoiH`INCt\\J\\UENU{Axv|F~DwGHeEEMeDheHd\\eHsg`u{UUUU@mAEMPQDqBId@@",
      "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPbOr_IorHbGtgD}F@RxPBuxc|_]^OTh}R_`CQ`MF@_`@_`A~"
    },
    "mass": 409.186273143011,
    "monoisotopicMass": 409.01885101411,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Cdp",
    "name": "Cytidine diphosphate diradical",
    "mf": "C9H13N3O10P2",
    "kind": "RNApp",
    "oneLetter": "C",
    "ocl": {
      "value": "fe{ph`I^[BgENbgHy`|[^E_CkcdRbbfrbTRdqrdYpIZjjjieijZbHfHQL`@",
      "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPb@K_cbpXbKtSItwPS]@Bux`Bo]\\lFGx@S]A~@C}~@Gx"
    },
    "mass": 385.1615357477025,
    "monoisotopicMass": 385.00761762482,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Gdp",
    "name": "Guanosine diphosphate diradical",
    "mf": "C10H13N5O10P2",
    "kind": "RNApp",
    "oneLetter": "G",
    "ocl": {
      "value": "fkhh`INCt\\J\\UENY{NCqmxM|EnNQJJJ[JIQJQHzIRLyxM^uUUUTkUSLuQDSDHfP@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_I`JHbGtgD}F@RxPBux`B_]^OTh}R_`CQ`B\\StXA~@C}~@Gx"
    },
    "mass": 425.1856780673293,
    "monoisotopicMass": 425.01376563368,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Tdp",
    "name": "Thymidine diphosphate diradical",
    "mf": "C10H14N2O11P2",
    "kind": "RNApp",
    "oneLetter": "T",
    "ocl": {
      "value": "fmgQh`I^aSbgQSglu`|[^C_@[bdls^rruo}LxDmUUUTruTsTQDqBId@@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPbOs_cbpXbGtSItwPS]@Bux`B_]\\lFBpX_`AMtGx@Owx@_`"
    },
    "mass": 400.172914111366,
    "monoisotopicMass": 400.00728327219,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Udp",
    "name": "Uridine diphosphate diradical",
    "mf": "C9H12N2O11P2",
    "kind": "RNApp",
    "oneLetter": "U",
    "ocl": {
      "value": "fe{Qh`I^aSbgQSehy`|[^E_CkcdRbbfrbTRdqrdYpIZjjjiejfZbHfHQL`@",
      "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPb@K_cbpXbKtSItwPS]@Bux`Bo]\\lFGx@S]A~@C}~@Gx"
    },
    "mass": 386.14629670651925,
    "monoisotopicMass": 385.99163320773005,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Atp",
    "name": "Adenosine triphosphate diradical",
    "mf": "C10H14N5O12P3",
    "kind": "RNAppp",
    "oneLetter": "A",
    "ocl": {
      "value": "e`TZCJ@IG@nahJNEHdliemgo`OFspZ|CoByqrIQQSYQJIRIGIRWRL\\^AU]UUUUPKPQMTuABDpaBX`@",
      "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPbOr_IorHbGtgD}F@RxS|uxc|_]^OTh}R_`CQ`MF@@hcW@A~_`A~@@A~Owx"
    },
    "mass": 489.16619066844174,
    "monoisotopicMass": 488.98518190347005,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 12
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Ctp",
    "name": "Cytidine triphosphate diradical",
    "mf": "C9H14N3O13P3",
    "kind": "RNAppp",
    "oneLetter": "C",
    "ocl": {
      "value": "fgqZ`I^[BgENbgOQsO\\Gc[pkxK|MnNQJJJ[JIQJSGJPzQg@ejjjjfVffjZbHfHQL`@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@K_cbpXbGtSItwPS]C|ux`B_]\\lFGx@S]@BbM\\B@Gy~@Gx@@Gx_`"
    },
    "mass": 465.1414532731331,
    "monoisotopicMass": 464.97394851418,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 13
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Gtp",
    "name": "Guanosine triphosphate diradical",
    "mf": "C10H14N5O13P3",
    "kind": "RNAppp",
    "oneLetter": "G",
    "ocl": {
      "value": "eh\\ZKJ@IG@nahJNEHdliemco`POFspZ|KoAyqrIQQSYQJIRIGQJQzQccpJkjjjjjeZjYZijbDIaBDq@@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_I`JHbGtgD}F@RxPBux`B_]^OTh}R_`CQ`B\\StX@BbM_|@Gy~@Gx@@Gx_`"
    },
    "mass": 505.16559559276,
    "monoisotopicMass": 504.98009652304,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 13
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Ttp",
    "name": "Thymidine triphosphate diradical",
    "mf": "C10H15N2O14P3",
    "kind": "RNAppp",
    "oneLetter": "T",
    "ocl": {
      "value": "eo`TGJ@IOHJNEGHdlnaiekg`OFspZ|Mo@yqrIQQSYQJIRY[ZPzQc`HjjjjjYZjVjZbDIaBDq@@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@K_cbpXbGtSItwPS]@Bux`B_]\\lFBpX_`AMt@JHupH@_gx@_`@@_c}~"
    },
    "mass": 480.15283163679663,
    "monoisotopicMass": 479.97361416155,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 14
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Utp",
    "name": "Uridine triphosphate diradical",
    "mf": "C9H13N2O14P3",
    "kind": "RNAppp",
    "oneLetter": "U",
    "ocl": {
      "value": "fgPz`I^aSbgQSeoQsO\\Gc[pkxK|MnNQJJJ[JIQJSGJPzQg@ejjjjfVjVjZbHfHQL`@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@K_cbpXbGtSItwPS]C|ux`B_]\\lFGx@S]@BbM\\B@Gy~@Gx@@Gx_`"
    },
    "mass": 466.12621423194986,
    "monoisotopicMass": 465.95796409709004,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 14
    }, {
      "symbol": "P",
      "number": 3
    }]
  }, {
    "symbol": "Ade",
    "name": "Adenosine diradical",
    "mf": "C10H11N5O3",
    "kind": "RNA",
    "oneLetter": "A",
    "ocl": {
      "value": "fbmia@IV|gLJ\\Axj\\Tef[vyWV\\]zJZjjj`PJ`bIbDSH@",
      "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~i|BEP{iVA@fUARU@QTADBYPId"
    },
    "mass": 249.22643809214986,
    "monoisotopicMass": 249.08618923539,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Cyt",
    "name": "Cytidine diradical",
    "mf": "C9H11N3O4",
    "kind": "RNA",
    "oneLetter": "C",
    "ocl": {
      "value": "fdypQ@INcBgK@|UNJRsM{\\~sg`uUUULmQDSDHfP@",
      "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~iRTBpgDq`@c`BNKB\\@c`"
    },
    "mass": 225.20170069684127,
    "monoisotopicMass": 225.0749558461,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 4
    }]
  }, {
    "symbol": "Gua",
    "name": "Guanosine diradical",
    "mf": "C10H11N5O4",
    "kind": "RNA",
    "oneLetter": "G",
    "ocl": {
      "value": "fj}hQ@IV|gLJ\\JCqTxiKLwmroKNN}EMUUUTkTuDQLPbY@@",
      "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~k|BEP{iVA@fUARU@QTADBYiVA@fP"
    },
    "mass": 265.22584301646816,
    "monoisotopicMass": 265.08110385496,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 4
    }]
  }, {
    "symbol": "Thy",
    "name": "Thymidine diradical",
    "mf": "C10H12N2O5",
    "kind": "RNA",
    "oneLetter": "T",
    "ocl": {
      "value": "fleQQ@INaSed`|UNJRsM{\\zlyxMUUUSMMDQLPbY@@",
      "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~iRTBpgDq`@c`BNKB\\lIpBN"
    },
    "mass": 240.21307906050478,
    "monoisotopicMass": 240.07462149347,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 5
    }]
  }, {
    "symbol": "Ura",
    "name": "Uridine diradical",
    "mf": "C9H10N2O5",
    "kind": "RNA",
    "oneLetter": "U",
    "ocl": {
      "value": "fdyQQ@INaSeh`|UNJRsM{\\~sg`uUUULsQDSDHfP@",
      "coordinates": "!BBOpH_UARccFPEP{PId{RpBN[~iRTBpgDq`@c`BNKB\\@c`"
    },
    "mass": 226.18646165565798,
    "monoisotopicMass": 226.05897142901,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 10
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 5
    }]
  }, {
    "symbol": "Dam",
    "name": "1,2′-O-dimethyladenosine monophosphate diradical 01A",
    "mf": "C12H16N5O6P",
    "kind": "NucleotideP",
    "oneLetter": "œ",
    "ocl": {
      "value": "feghs@E^ct\\J\\udhOEw`eqrIQQQKZIQJQIiLxFK^uUUUUKLtuQDSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@SuH"
    },
    "mass": 357.2595904272741,
    "monoisotopicMass": 357.08382025367,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dgm",
    "name": "1,2′-O-dimethylguanosine monophosphate diradical 01G",
    "mf": "C12H16N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "ε",
    "ocl": {
      "value": "fmwis@E^ct\\J\\udlp^KoAKcdRbbbVtRbTbSbSNAbwmUUUURsMSUDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@B\\StPAOT`"
    },
    "mass": 373.2589953515923,
    "monoisotopicMass": 373.07873487324,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dim",
    "name": "1,2′-O-dimethylinosine monophosphate diradical 019A",
    "mf": "C12O7N4H15P",
    "kind": "NucleotideP",
    "oneLetter": "ξ",
    "ocl": {
      "value": "fegIs@E^cvENZrTXOEw`eqrIQQQKZIQJQIiLxFK^uUUUUKLtuQDSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@SuH"
    },
    "mass": 358.2443513860907,
    "monoisotopicMass": 358.06783583658,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 4
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Tia",
    "name": "2- methylthiomethylenethio-N6-isopentenyl-adenosine monophosphate diradical",
    "mf": "C17H24N5O6PS2",
    "kind": "NucleotideP",
    "oneLetter": "£",
    "ocl": {
      "value": "eh\\ZFJ@IG@nahJNEDl`OFspb\\V`cXHrIQQSYQJIRINIYIKQccpJkjjjjjAfBJjfjBDIaBDq@@",
      "coordinates": "!BpBYTvxBNFY|bEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~H@hc|_`BH_Xa}b@JH@gx@bGvH@h`B_`BH_P"
    },
    "mass": 489.50637075565066,
    "monoisotopicMass": 489.09056286031,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 17
    }, {
      "symbol": "H",
      "number": 24
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 2
    }]
  }, {
    "symbol": "Mhc",
    "name": "2′‐O‐Methyl-5-hydroxymethylcytidine monophosphate diradical",
    "mf": "C11H16N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "¡",
    "ocl": {
      "value": "fikpK@EA{BgM^rTXOEw`eqrIQQQKZIQJSJigHujjjjifYjkBHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@HoTuOSU@HC~NKA`HoQLgSUAMT@a}oS_|BBpXKAaMT@CQ"
    },
    "mass": 349.2342579562838,
    "monoisotopicMass": 349.06750148395,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Odg",
    "name": "N2,2′-O-dimethylguanosine monophosphate diradical 02G",
    "mf": "C12H16N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "γ",
    "ocl": {
      "value": "fmwis@E^ct\\J\\udlp^KoAKcdRbbbVtRbTbSbsNAbwmUUUURsMSUDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@B\\StPAOT`"
    },
    "mass": 373.2589953515923,
    "monoisotopicMass": 373.07873487324,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ntg",
    "name": "N2,N2,2′-O-trimethylguanosine monophosphate diradical 022G",
    "mf": "C13H18N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "|",
    "ocl": {
      "value": "fcois@E^ct\\J\\udlp^KoAKcdRbbbVtRbTbSbTYpLVcjjjjjVYjZjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuHgD}D@tPBNOt}R"
    },
    "mass": 387.2856127564392,
    "monoisotopicMass": 387.0943849377,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Otg",
    "name": "N2,7,2′-O-trimethylguanosine monophosphate diradical 027G",
    "mf": "C13H20N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "æ",
    "ocl": {
      "value": "fcoisBE^bN\\J\\udjp^KoAKcFU}dRbbbVtRbTbRlQYpLVcjjjjjVYjjjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKFPMD@IqOQ@D}R"
    },
    "mass": 389.30149426455074,
    "monoisotopicMass": 389.11003500216,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Rya",
    "name": "2′-O-ribosyladenosine monophosphate diradical 00A",
    "mf": "C15H20N5O9P",
    "kind": "NucleotideP",
    "oneLetter": "^",
    "ocl": {
      "value": "e`\\ZIL@DaegobFAIO@hlm`OGSp\\\\\\bbbfrRbdTT\\rbRQUCDQTrusuUUUUMUU@pET@@@",
      "coordinates": "!BIlAKaMARw}DBbMF@bGuMtHc|KAbH_ZU`@GzH_WwW@h`XKFjKB_jXB\\SiVA`zmG_Irp_hQKctvOSR\\lIrp"
    },
    "mass": 445.3217759066577,
    "monoisotopicMass": 445.09986424130005,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ryg",
    "name": "2′-O-ribosylguanosine monophosphate diradical 00G",
    "mf": "C15H20N5O10P",
    "kind": "NucleotideP",
    "oneLetter": "ℑ",
    "ocl": {
      "value": "ehRZEL@DaegobFAIO@hlm`POGSp\\\\\\bbbfrRbdTT\\rbRQbhXbJfVn^jjjjijjjVZfj@@@",
      "coordinates": "!BIlAKaMARw}DBbMF@bGuMtH`BKAbH_ZU`@GzH_WwW@h`XKFjKB_jXB\\SiVA`zmG_Irp_hQKctvOSR\\lt]|gK@"
    },
    "mass": 461.321180830976,
    "monoisotopicMass": 461.09477886087,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Tmu",
    "name": "2-thio-2′-O-methyluridine monophosphate diradical 02U",
    "mf": "C10H13N2O7PS",
    "kind": "NucleotideP",
    "oneLetter": "∏",
    "ocl": {
      "value": "fncQp`EAaSfleZCq]x^BDnNQJJJI[QJIRYlyFmUUUULsSQDSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@"
    },
    "mass": 336.25837906774416,
    "monoisotopicMass": 336.01810893766003,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Dmut",
    "name": "3,2′-O-dimethyluridine monophosphate diradical 03U",
    "mf": "C11H15N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "σ",
    "ocl": {
      "value": "fasPK@EAaSfoYKtGb{pRxyDhhhemDheIhv\\cVjjjjfYjZHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXOxyMT@"
    },
    "mass": 334.2196139907822,
    "monoisotopicMass": 334.05660244729,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Amc",
    "name": "N4-acetyl-2′-O-methylcytidine monophosphate diradical 042C",
    "mf": "C12H16N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "ℵ",
    "ocl": {
      "value": "fe{pK@EA[BgM^rTXOEw`eqrIQQQKZIQJSMJLyFmUUUULsMMQDSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@caLgSU@"
    },
    "mass": 361.244993853019,
    "monoisotopicMass": 361.06750148395,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Tmc",
    "name": "N4,N4,2′-O-trimethylcytidine monophosphate diradical 044C",
    "mf": "C12H18N3O7P",
    "kind": "NucleotideP",
    "oneLetter": "β",
    "ocl": {
      "value": "fikqs@EA[BgM^rTGb{pRxyDhhhemDheIfhsdZuUUUTsLuTQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@cbpX"
    },
    "mass": 347.2614704368123,
    "monoisotopicMass": 347.08823692884005,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dcy",
    "name": "N4,2′-O-dimethylcytidine monophosphate diradical 04C",
    "mf": "C11H16N3O7P",
    "kind": "NucleotideP",
    "oneLetter": "λ",
    "ocl": {
      "value": "fasqs@EA[BgM^rTGb{pRxyDhhhemDheIff\\cVjjjjfYfjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@lF@"
    },
    "mass": 333.23485303196554,
    "monoisotopicMass": 333.07258686438,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Muo",
    "name": "2′-O-methyluridine 5-oxyacetic acid methyl ester monophosphate diradical 0503U",
    "mf": "C13H17N2O11P",
    "kind": "NucleotideP",
    "oneLetter": "Ͽ",
    "ocl": {
      "value": "fkoQk@EAaSfoYJwj}`|W^BWGHeEEDmheDiLjlif\\cVjjjjfYjZZhbIbDSH@",
      "coordinates": "!BKAb@tURD@m\\YpMAMpBYMcvjbOplIwx@bGuMc}\\Bb@JH@dvOcuKPSXa}bGvHH`BbGu~Oxc|bGt"
    },
    "mass": 408.25518206531905,
    "monoisotopicMass": 408.05699637046,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 17
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Xmu",
    "name": "5-carboxymethylaminomethyl-2′-O-methyluridine monophosphate diradical 051U",
    "mf": "C13H18N3O10P",
    "kind": "NucleotideP",
    "oneLetter": ")",
    "ocl": {
      "value": "fkopk@EAGBgM^rWns`|W^BWGHeEEDmheDiLjleF\\cVjjjjfYjZfhbIbDSH@",
      "coordinates": "!BKAb@tURD@m\\YpMAMpBYMcvjb@HlIwx@bGuMc}\\Bb@JH@dvOcuKPSXa}bGvH@h`BbGvH@gx@bKt"
    },
    "mass": 407.2704211065024,
    "monoisotopicMass": 407.07298078755,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mmu",
    "name": "5-methoxycarbonylmethyl-2′-O-methyluridine monophosphate diradical 0521U",
    "mf": "C13H17N2O10P",
    "kind": "NucleotideP",
    "oneLetter": "∩",
    "ocl": {
      "value": "fcwPk@EAaSfoYKvZp^KoAKcdRbbbVtRbTfUVfYrMZjjjjYfifjHbXaDr@@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lI}mK_`B@cm\\Bb@HlI}]}_`A~@BpgIqLXKH`Bb@I~@Ha}_c~HHa}"
    },
    "mass": 392.2557771410008,
    "monoisotopicMass": 392.06208175089,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 17
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Cue",
    "name": "5-(carboxyhydroxymethyl)-2′-O-methyluridine methyl ester monophosphate diradical 0522U",
    "mf": "C13H17N2O11P",
    "kind": "NucleotideP",
    "oneLetter": "∩",
    "ocl": {
      "value": "fkoQk@EAaSfoYKtZ}`|W^BWGHeEEDmheDiLjhYf\\cVjjjjfYjZZhbIbDSH@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lI}mK_`B@cm\\Bb@HlI}]}_`A~@BpgIqLXKH`Bb@I~@Gx@bGu~Oxc|bGt"
    },
    "mass": 408.25518206531905,
    "monoisotopicMass": 408.05699637046,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 17
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Cyu",
    "name": "5-carbamoylmethyl-2′-O-methyluridine monophosphate diradical 053U",
    "mf": "C12H16N3O9P",
    "kind": "NucleotideP",
    "oneLetter": "~",
    "ocl": {
      "value": "fmgqK@EAWBgM^rWlp^KoAKcdRbbbVtRbTfUVcNQkUUUUSLuLuDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXKAaMTDuPOxxlF@"
    },
    "mass": 377.24439877733727,
    "monoisotopicMass": 377.06241610352,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ipu",
    "name": "5-(isopentenylaminomethyl)-2′-O-methyluridine monophosphate diradical 0583U",
    "mf": "C16H24N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "¼",
    "ocl": {
      "value": "fgpK@EAGBgM^rWhOEw`eqrIQQQKZIQJSJkIJLyFmUUUULsTuMTQDqBId@@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lI}mK_`B@cm\\Bb@HlI}]}_`A~@BpgIqLXKH`Bb@I~@Ha}b@JH_Xc|_`BH_P"
    },
    "mass": 417.35146347240624,
    "monoisotopicMass": 417.13010174179004,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 16
    }, {
      "symbol": "H",
      "number": 24
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mcy",
    "name": "5,2′-O-dimethylcytidine monophosphate diradical monophosphate diradical 05C",
    "mf": "C11H16N3O7P",
    "kind": "NucleotideP",
    "oneLetter": "τ",
    "ocl": {
      "value": "fasqs@EA{BgM^rTGb{pRxyDhhhemDheIeV\\cVjjjjfYfjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXKAaMT@"
    },
    "mass": 333.23485303196554,
    "monoisotopicMass": 333.07258686438,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dmuf",
    "name": "5,2′-O-dimethyluridine monophosphate diradical 05U",
    "mf": "C11H15N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "\\",
    "ocl": {
      "value": "fasPK@EAaSfoYKtGb{pRxyDhhhemDheIeV\\cVjjjjfYjZHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXKAaMT@"
    },
    "mass": 334.2196139907822,
    "monoisotopicMass": 334.05660244729,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Tma",
    "name": "N6,N6,2′-O-trimethyladenosine monophosphate diradical 066A",
    "mf": "C13H18N5O6P",
    "kind": "NucleotideP",
    "oneLetter": "η",
    "ocl": {
      "value": "fmwhs@E^ct\\J\\udhOEw`eqrIQQQKZIQJQIkQg@q[vjjjj`Y`JjBHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@SuHXK@"
    },
    "mass": 371.2862078321209,
    "monoisotopicMass": 371.09947031813005,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Nda",
    "name": "N6,2′-O-dimethyladenosine monophosphate diradical 06A",
    "mf": "C12H16N5O6P",
    "kind": "NucleotideP",
    "oneLetter": "χ",
    "ocl": {
      "value": "feghs@E^ct\\J\\udhOEw`eqrIQQQKZIQJQIkLxFK^uUUUTCLAUADSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@FBp"
    },
    "mass": 357.2595904272741,
    "monoisotopicMass": 357.08382025367,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Fmc",
    "name": "5-formyl-2′-O-methylcytidine monophosphate diradical 071C",
    "mf": "C10H12N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "°",
    "ocl": {
      "value": "faspK@I^[BgENSghOFwaEqrIQQSYQJIRYULxDmUUUTsLttQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
    },
    "mass": 333.1917590433254,
    "monoisotopicMass": 333.03620135502996,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Omi",
    "name": "2′-O-methylinosine monophosphate diradical 09A",
    "mf": "C11H13N4O7P",
    "kind": "NucleotideP",
    "oneLetter": "≤",
    "ocl": {
      "value": "fi{Is@E^cvENZrTXOEw`eqrIQQQKZIQJQIig@q[vjjjjiYffhbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@"
    },
    "mass": 344.21773398124395,
    "monoisotopicMass": 344.05218577211997,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 4
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Opu",
    "name": "2′-O-methylpseudouridine monophosphate diradical 09U",
    "mf": "C10H13N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "Z",
    "ocl": {
      "value": "fncPK@@qaSfoYJtGb{pRxyDhhhemDheIfsdZuUUULuMMDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@"
    },
    "mass": 320.1929965859354,
    "monoisotopicMass": 320.04095238282997,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Oma",
    "name": "2′-O-methyladenosine monophosphate diradical 0A",
    "mf": "C11H14N5O6P",
    "kind": "NucleotideP",
    "oneLetter": ":",
    "ocl": {
      "value": "fi{hs@E^ct\\J\\udhOEw`eqrIQQQKZIQJQIig@q[vjjjj`Y`J`bIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@MD@"
    },
    "mass": 343.2329730224273,
    "monoisotopicMass": 343.06817018921,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Omc",
    "name": "2′-O-methylcytidine monophosphate diradical 0C",
    "mf": "C10H14N3O7P",
    "kind": "NucleotideP",
    "oneLetter": "B",
    "ocl": {
      "value": "fncqs@EA[BgM^rTGb{pRxyDhhhemDheIfsdZuUUUTsLuDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@"
    },
    "mass": 319.2082356271187,
    "monoisotopicMass": 319.05693679992004,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Omg",
    "name": "2′-O-methylguanosine monophosphate diradical 0G",
    "mf": "C11H14N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "#",
    "ocl": {
      "value": "fegis@E^ct\\J\\udlp^KoAKcdRbbbVtRbTbSbYpLV}jjjjjVYjZbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@HoTuOSU@HEF@`H_R\\StPAKA@a}_S_|BD}RSuKQ@B\\StP@"
    },
    "mass": 359.23237794674554,
    "monoisotopicMass": 359.06308480878,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Omu",
    "name": "2′-O-methyluridinemonophosphate diradical 0U",
    "mf": "C10H13N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "J",
    "ocl": {
      "value": "fncPK@EAaSfoYJtGb{pRxyDhhhemDheIfsdZuUUUTsMMDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuOSU@HC~NKA`H_QLgSUAMT@a}_S_|BBpXSU@"
    },
    "mass": 320.1929965859354,
    "monoisotopicMass": 320.04095238282997,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Cdg",
    "name": "7-cyano-7-deazaguanosine monophosphate diradical 100G",
    "mf": "C12H12N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "φ",
    "ocl": {
      "value": "fmwis@INzM\\J\\TgLp^MoBKcdRbbfrbTRdRUbSN^CWmUUUUKLuSuDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StPCFP@"
    },
    "mass": 369.22723233536925,
    "monoisotopicMass": 369.04743474432,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Azg",
    "name": "7-aminomethyl-7-deazaguanosine monophosphate diradical 101G",
    "mf": "C12H16N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "∉",
    "ocl": {
      "value": "fmwis@INzM\\J\\TgLp^MoBKcdRbbfrbTRdRUbSN^CWmUUUUKLuSUDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StPA`z`"
    },
    "mass": 373.2589953515923,
    "monoisotopicMass": 373.07873487324,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Eqo",
    "name": "epoxyqueuosine monophosphate diradical 102G",
    "mf": "C17H22N5O10P",
    "kind": "NucleotideP",
    "oneLetter": "ς",
    "ocl": {
      "value": "el^ZEL@IGNaehJNEDlig`TPOFspb\\\\bTTTvTRbTbRlRjbbfXx|Bjz~aAajjjjiYfjZjjjjHPfDHSD@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StP@{ULY@TEIKA@a}tPA}BOpHAEP"
    },
    "mass": 487.3585341325581,
    "monoisotopicMass": 487.11042892533,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 17
    }, {
      "symbol": "H",
      "number": 22
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Aes",
    "name": "archaeosine monophosphate diradical 103G",
    "mf": "C12H15N6O7P",
    "kind": "NucleotideP",
    "oneLetter": "(",
    "ocl": {
      "value": "fcoYs@INzM^xTxiNY`|[^DWGHeEEMeDheHdkDhsg`u{UUUURsMTmTQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StP@{UFCj"
    },
    "mass": 386.2577578089824,
    "monoisotopicMass": 386.07398384544,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Goq",
    "name": "galactosyl-queuosine monophosphate diradical 104G",
    "mf": "C23H32N5O14P",
    "kind": "NucleotideP",
    "oneLetter": "9",
    "ocl": {
      "value": "ekXzGL@IGNaehJNEDliod\\VU]SPOFspb\\\\bTTTvTRbTbRlRjbTrTrbfRXx|Bjz^AyEjjjjiYfjZijjjjjjbDIaBDq@@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_IorHbGtgD}F@RxRH_WwW@hbOTh}RIlCQ`B\\StXC[UB[@RxSPT`JHbGwQ`H`BaEQ~@Ha}bOq~Ox`BbGu~@Ha}bOrH@`"
    },
    "mass": 633.4999767508004,
    "monoisotopicMass": 633.16833772591,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 23
    }, {
      "symbol": "H",
      "number": 32
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 14
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Gaq",
    "name": "glutamyl-queuosine monophosphate diradical105G",
    "mf": "C22H29N6O12P",
    "kind": "NucleotideP",
    "oneLetter": "⊄",
    "ocl": {
      "value": "emWVCL@IGNaejXJNEDlioh\\YUPOFspb\\\\bTTTvTRbTbRlRjbTJTtrTXx|Bjz^AjjjjiYfjZijfjfjbDIaBDq@@",
      "coordinates": "!BTmB@c`JHUMmMtL@YtEHYgxQTaDoQ`L@YFY|gKMARH`Ygy|fpAfN`Hz@`H{PTb\\ltEIRtHBNHaTv|@YFYPTha}b@I~@Ha}_c~H@ha}bOq~@Ha}"
    },
    "mass": 600.473311954707,
    "monoisotopicMass": 600.15810739451,
    "unsaturation": 22,
    "elements": [{
      "symbol": "C",
      "number": 22
    }, {
      "symbol": "H",
      "number": 29
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 12
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Moq",
    "name": "mannosyl-queuosine monophosphate diradical 106G",
    "mf": "C23H32N5O14P",
    "kind": "NucleotideP",
    "oneLetter": "8",
    "ocl": {
      "value": "ekXzGL@IGNaehJNEDliod\\VU]SPOFspb\\\\bTTTvTRbTbRlRjbTrTrbfRXx|Bjz^AyEjjjjiYfjZijjjjjjbDIaBDq@@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_IorHbGtgD}F@RxRH_WwW@hbOTh}RIlCQ`B\\StXC[UB[@RxSPT`JHbGwQ`H`BaEQ~@Ha}bOq~Ox`BbGu~@Ha}bOrH@`"
    },
    "mass": 633.4999767508004,
    "monoisotopicMass": 633.16833772591,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 23
    }, {
      "symbol": "H",
      "number": 32
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 14
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Qus",
    "name": "queuosine monophosphate diradical 10G",
    "mf": "C17H22N5O9P",
    "kind": "NucleotideP",
    "oneLetter": "Q",
    "ocl": {
      "value": "edZZIL@IGNaehJNEDliohPOFspb\\\\bTTTvTRbTbRlRjbTKGG`UWSpMUUUUKLuSUMUTPaLHPfH@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPHoWtw@aOTd}RqdCQ@B\\StP@{ULY@RpQPTopHBGwQ@@QT"
    },
    "mass": 471.35912920823984,
    "monoisotopicMass": 471.11551430576,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 17
    }, {
      "symbol": "H",
      "number": 22
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Cpo",
    "name": "1-methyl-3-(3-amino-3-carboxypropyl)pseudouridine monophosphate diradical 1309U",
    "mf": "C14H20N3O10P",
    "kind": "NucleotideP",
    "oneLetter": "α",
    "ocl": {
      "value": "fgpk@OAWBgENSgi{`|[^DWGHeEEMeDheIhjbihs`RuUUTsTuSUMQDSDHfP@",
      "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}DqbH@gx_c|SFA`lIqOW_Xa}uwu~Ox`BbGu~Ox`B_`BH_P"
    },
    "mass": 421.2970385113492,
    "monoisotopicMass": 421.08863085201,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 14
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mls",
    "name": "1-methylinosine monophosphate diradical 19A",
    "mf": "C11H13N4O7P",
    "kind": "NucleotideP",
    "oneLetter": "O",
    "ocl": {
      "value": "fi{Is@INBvENJSghOFwaEqrIQQSYQJIRIMIgOAjvjjjjefZZhbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}R"
    },
    "mass": 344.21773398124395,
    "monoisotopicMass": 344.05218577211997,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 4
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mpu",
    "name": "1-methylpseudouridine monophosphate diradical 19U",
    "mf": "C10H13N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "]",
    "ocl": {
      "value": "fncPK@OAaSbgIrtGc[pbxyDhhilheDiLjs`RuUUTsTuMDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
    },
    "mass": 320.1929965859354,
    "monoisotopicMass": 320.04095238282997,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mad",
    "name": "1-methyladenosine monophosphate diradical 1A",
    "mf": "C11H14N5O6P",
    "kind": "NucleotideP",
    "oneLetter": "\"",
    "ocl": {
      "value": "fi{hs@INBwlJ\\TgHOFwaEqrIQQSYQJIRIMIgOAjvjjjjefZZhbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}R"
    },
    "mass": 343.2329730224273,
    "monoisotopicMass": 343.06817018921,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mgs",
    "name": "1-methylguanosine monophosphate diradical 1G",
    "mf": "C11H14N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "K",
    "ocl": {
      "value": "fegis@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\RYspZmjjjjiYfijbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtP@gD}D@SuH"
    },
    "mass": 359.23237794674554,
    "monoisotopicMass": 359.06308480878,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Msu",
    "name": "5-aminomethyl-2-selenouridine monophosphate diradical 20510U",
    "mf": "C10H14N3O7PSe",
    "kind": "NucleotideP",
    "oneLetter": "π",
    "ocl": {
      "value": "fasqp`I^{BgEIrtGc[p\\bQ\\\\bTTTvTRbTfUSNAKUUUULsTuDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
    },
    "mass": 398.1676241841323,
    "monoisotopicMass": 398.97345859992004,
    "unsaturation": null,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "Se",
      "number": 1
    }]
  }, {
    "symbol": "Mse",
    "name": "5-methylaminomethyl-2-selenouridine monophosphate diradical 20511U",
    "mf": "C11H16N3O7PSe",
    "kind": "NucleotideP",
    "oneLetter": "≅",
    "ocl": {
      "value": "fikqp`I^{BgEIrtGc[p\\bQ\\\\bTTTvTRbTfUVYpIZjjjifZfjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTBpX"
    },
    "mass": 412.19424158897914,
    "monoisotopicMass": 412.98910866438,
    "unsaturation": null,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "Se",
      "number": 1
    }]
  }, {
    "symbol": "Cse",
    "name": "5-carboxymethylaminomethyl-2-selenouridine monophosphate diradical 2051U",
    "mf": "C12H16N3O9PSe",
    "kind": "NucleotideP",
    "oneLetter": "⊥",
    "ocl": {
      "value": "fcwqH`I^{BgEIru^p^MoArIEqrIQQSYQJIRYUYJLxDmUUUTsMSTuDQLPbY@@",
      "coordinates": "!BKAb@tURDM\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@I~@Ha}"
    },
    "mass": 456.20378733435086,
    "monoisotopicMass": 456.97893790352,
    "unsaturation": null,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "Se",
      "number": 1
    }]
  }, {
    "symbol": "Agm",
    "name": "agmatidine monophosphate diradical 20C",
    "mf": "C14H26N7O6P",
    "kind": "NucleotideP",
    "oneLetter": "¿",
    "ocl": {
      "value": "fgxs@I^BuY{piqR\\`|[^DWGHeEEMeDeEHmUddhsgbuUUUSTuUUMIDSDHfP@",
      "coordinates": "!BDqc_tTnD_]\\fpH}MgrYRc}_|Dr_W_Wx@ThWM_|bOqRc}ARctu~@Gx@urH@gx@b@I~@H`BbGu~@@"
    },
    "mass": 419.373876184194,
    "monoisotopicMass": 419.16821858483,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 14
    }, {
      "symbol": "H",
      "number": 26
    }, {
      "symbol": "N",
      "number": 7
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Sou",
    "name": "2-selenouridine monophosphate diradical 20U",
    "mf": "C9H11N2O7PSe",
    "kind": "NucleotideP",
    "oneLetter": "ω",
    "ocl": {
      "value": "ff}Qp`I^aSbdyjCqmxNQHnNQJJJ[JIQJSMg@ejjjjfYihbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
    },
    "mass": 369.1263628137839,
    "monoisotopicMass": 369.9469094988,
    "unsaturation": null,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "Se",
      "number": 1
    }]
  }, {
    "symbol": "Agu",
    "name": "5-aminomethyl-2-geranylthiouridine monophosphate diradical 21510U",
    "mf": "C20H30N3O7PS",
    "kind": "NucleotideP",
    "oneLetter": "Δ",
    "ocl": {
      "value": "ed\\\\NB@IOIhJNEDla`OFsp\\BHgGHeEEMeDheHdjdcEdhqpEUUUUURsUSMTuQBDpaBXdDt@",
      "coordinates": "!BDr__cdo[_X`fgx}RgqeRtM]}Dqa~O}\\BTmBH_]]}uwuRtMAMcuI~O}\\BupJH_]]}_`A~Oxa}uwu~Oxa}_cW_Xa}"
    },
    "mass": 487.5074340654907,
    "monoisotopicMass": 487.15420849000003,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 20
    }, {
      "symbol": "H",
      "number": 30
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mgu",
    "name": "5-methylaminomethyl-2-geranylthiouridine monophosphate diradical 21511U",
    "mf": "C21H32N3O7PS",
    "kind": "NucleotideP",
    "oneLetter": "h",
    "ocl": {
      "value": "elR\\NB@IOIhJNEDla`OFsp\\BHgGHeEEMeDheHdjdlileFN@jjjjjjVZjYjijbDIaBDqHIh",
      "coordinates": "!BTv^cbn{__@fw|}RwqeRdK]}Tva~_{_|TiCp_[]}mwuRdIAMsuI~_{]|mwsp_[]}mwu~_{_||Gvw_Wy|Gu~_{]}|Gt"
    },
    "mass": 501.5340514703375,
    "monoisotopicMass": 501.16985855446006,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 21
    }, {
      "symbol": "H",
      "number": 32
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Cgu",
    "name": "5-carboxymethylaminomethyl-2-geranylthiouridine monophosphate diradical 2151U",
    "mf": "C22H32N3O9PS",
    "kind": "NucleotideP",
    "oneLetter": "f",
    "ocl": {
      "value": "ef^\\IB@IOIhJNEDla`XPOFsp\\BHgGHeEEMeDheHdjdlhehbhqpEUUUUURsUSMUMMTPaLHPfIAM@",
      "coordinates": "!BTv^cbn{_@fw|}RwqeRdK]}Tva~_{]|TiCp[_}muRdIAMsuI~_{]|mwsp_[]}mwu~_{]||Gvw_[_}_g}~_{]||Ou~_{]}|Gt"
    },
    "mass": 545.5435972157093,
    "monoisotopicMass": 545.1596877935999,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 22
    }, {
      "symbol": "H",
      "number": 32
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mha",
    "name": "2-methylthio-N6-(cis-hydroxyisopentenyl) adenosine monophosphate diradical 2160A",
    "mf": "C16H22N5O7PS",
    "kind": "NucleotideP",
    "oneLetter": "≠",
    "ocl": {
      "value": "e`TZNB@IG@nahJNEDlo`OFspb\\V`cHeEEMeDheHdxeleDqqxEUuUUUU@sAETuTDHSBDIbP[P",
      "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]WHc|TmCQw}~N`ME~@Gx@upJH@h`B_`BH_X`BbGvHGxbGt"
    },
    "mass": 459.41437086899504,
    "monoisotopicMass": 459.09775624102,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 16
    }, {
      "symbol": "H",
      "number": 22
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mpa",
    "name": "2-methylthio-N6-isopentenyladenosine monophosphate diradical 2161A",
    "mf": "C16H22N5O6PS",
    "kind": "NucleotideP",
    "oneLetter": "*",
    "ocl": {
      "value": "eohZFB@IG@nahJNEDl`OFspb\\V`cHeEEMeDheHdxeleFNO@jnjjjjhFXHjfjBDIaBDq@@",
      "coordinates": "!BpBYTvxBNFY|bEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~H@h`B_`BH_Xa}bOrH@ha}b@I~@Ha}"
    },
    "mass": 443.4149659446768,
    "monoisotopicMass": 443.10284162145,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 16
    }, {
      "symbol": "H",
      "number": 22
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mca",
    "name": "2-methylthio-N6-threonylcarbamoyladenosine monophosphate diradical 2162A",
    "mf": "C16H21N6O10PS",
    "kind": "NucleotideP",
    "oneLetter": "[",
    "ocl": {
      "value": "ebVVEB@IG@nachJNEDlm`XTPOFspb\\V`cHeEEMeDheHdxemLhhhqqxEUuUUUU@sAESUMUABDpaBX`@",
      "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@upJH@h`B_`BH_Wxb@JH_WxbOrHo]^}_`BH_P"
    },
    "mass": 520.4113480993399,
    "monoisotopicMass": 520.07774907193,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 16
    }, {
      "symbol": "H",
      "number": 21
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mva",
    "name": "2-methylthio-N6-hydroxynorvalylcarbamoyladenosine monophosphate diradical 2163A",
    "mf": "C17H23N6O10PS",
    "kind": "NucleotideP",
    "oneLetter": "≈",
    "ocl": {
      "value": "ej^VEB@IG@nachJNEDlm`XTPOFspb\\V`cHeEEMeDheHdxemLhhiVNO@jnjjjjhFXHjZijjBDIaBDq@@",
      "coordinates": "!BpBYTvxBNFY|BbEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~H@h`B_`BH_Xa}bOrH@gx@bGvHGx@bGwW@h`B_c~H@ha}"
    },
    "mass": 534.4379655041866,
    "monoisotopicMass": 534.09339913639,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 17
    }, {
      "symbol": "H",
      "number": 23
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mya",
    "name": "2-methylthio cyclic N6-threonylcarbamoyladenosine monophosphate diradical 2164A",
    "mf": "C17H20N5O9PS",
    "kind": "NucleotideP",
    "oneLetter": "ÿ",
    "ocl": {
      "value": "elVZIB@IG@nkhJNEDlcghPOFspb\\V`cHeEEMeDheHdxeihiUFNO@jnkojjjjhFXHjfZjbHPfDHSD@@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_IorHbGtgD}F@RxRH_WwW@hbOTh}RIqOQ`MF@cuKW@hQTcttfpL@YS]@BbGvH@Gx"
    },
    "mass": 501.4080351062552,
    "monoisotopicMass": 501.07193541570007,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 17
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Hta",
    "name": "hydroxy-N6-threonylcarbamoyladenosine monophosphate diradical 2165A",
    "mf": "C15H19N6O11P",
    "kind": "NucleotideP",
    "oneLetter": "«",
    "ocl": {
      "value": "elZVML@IG@fnehJNEDligo`TPOFspb\\\\bTTTvTRbTbSVTrbbeXx|BjZjjjj`Y`JZijjBDIaBDq@@",
      "coordinates": "!BpBYTvxBNFY|bEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~HH`BbGvH_Xc|_`BH_Xc|_`BH_]_|bOq~Oxc|bGt"
    },
    "mass": 490.31934821268436,
    "monoisotopicMass": 490.08494245264,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 19
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Lyd",
    "name": "2-lysidine monophosphate diradical 21C",
    "mf": "C15H24N5O8P",
    "kind": "NucleotideP",
    "oneLetter": "}",
    "ocl": {
      "value": "eo`ZAL@IGOFmhJNEDlkg`OFspb\\\\bTTTvTRbTbSVRTtXxBJjjjjfYjZjfhaBXPaLP@",
      "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}Dqa~Oxc|_c|SFA`lIqOW_Xa}_c~HHa}bOrH_WxbOq~@Ha}"
    },
    "mass": 433.3541339985626,
    "monoisotopicMass": 433.13624975064994,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 24
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Gtu",
    "name": "2-geranylthiouridine monophosphate diradical 21U",
    "mf": "C19H27N2O7PS",
    "kind": "NucleotideP",
    "oneLetter": "Γ",
    "ocl": {
      "value": "e`XTNB@IOHJNEDln`OFsp\\BHgGHeEEMeDheHdtmEdhqpEUUUUURsUKUMTPaLHPfIAu@",
      "coordinates": "!BTv^cbn{__@fw|}RwqeRdK]}Tva~_{_|TiCp_[]}mwuRdIAMsuI~_{]||Gvw_Wy|Gvw_Wy|Gu~_{]}|Gt"
    },
    "mass": 458.46617269514235,
    "monoisotopicMass": 458.12765938888003,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 19
    }, {
      "symbol": "H",
      "number": 27
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Tyg",
    "name": "N2,N2,7-trimethylguanosine cap monophosphate diradical (cap TMG) 2279553N",
    "mf": "C13H20N5O10P2",
    "kind": "NucleotideP",
    "oneLetter": "¶",
    "ocl": {
      "value": "e`TZEBHIG@aihJNEHdleck`OFspz|MgDJTef[vVVe_gifNO@jijjjjjUijifjhaBXPaLP@",
      "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPbOr_I`JHbGtgD}F@RxS|uxc|_]^OTh}RIlA~@B\\StXCQ`Gx@Owx@_h{_cuH"
    },
    "mass": 468.2734710359255,
    "monoisotopicMass": 468.06854085929,
    "unsaturation": 13,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Tmg",
    "name": "N2,N2,7-trimethylguanosine monophosphate diradical 227G",
    "mf": "C13H20N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "∠",
    "ocl": {
      "value": "fcoisBINCt\\J\\TgLp^MoBKbFY}dRbbfrbTRdRUbtYspZcjjjjiYfjjjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}Rqd@gD}D@tPBNOt}R"
    },
    "mass": 389.30149426455074,
    "monoisotopicMass": 389.11003500216,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dgu",
    "name": "N2,N2-dimethylguanosine monophosphate diradical 22G",
    "mf": "C12H16N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "R",
    "ocl": {
      "value": "fmwis@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\RcN^CWmUUUUKLuMUDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RIqOQ@MD@cc}OT`"
    },
    "mass": 373.2589953515923,
    "monoisotopicMass": 373.07873487324,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Atu",
    "name": "5-aminomethyl-2-thiouridine monophosphate diradical 2510U",
    "mf": "C10H14N3O7PS",
    "kind": "NucleotideP",
    "oneLetter": "∫",
    "ocl": {
      "value": "fasqp`I^{BgEIrtGc[p\\DQ\\\\bTTTvTRbTfUSNAKUUUULsTuDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
    },
    "mass": 351.27302303324575,
    "monoisotopicMass": 351.02900797432005,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mou",
    "name": "5-methylaminomethyl-2-thiouridine monophosphate diradical 2511U",
    "mf": "C11H16N3O7PS",
    "kind": "NucleotideP",
    "oneLetter": "S",
    "ocl": {
      "value": "fikqp`I^{BgEIrtGc[p\\DQ\\\\bTTTvTRbTfUVYpIZjjjifZfjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTBpX"
    },
    "mass": 365.2996404380926,
    "monoisotopicMass": 365.04465803878,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Ctu",
    "name": "5-carboxymethylaminomethyl-2-thiouridine monophosphate diradical 251U",
    "mf": "C12H16N3O9PS",
    "kind": "NucleotideP",
    "oneLetter": "$",
    "ocl": {
      "value": "fcwqH`I^{BgEIru^p^MoApQEqrIQQSYQJIRYUYJLxDmUUUTsMSTuDQLPbY@@",
      "coordinates": "!BKAb@tURDM\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@I~@Ha}"
    },
    "mass": 409.3091861834643,
    "monoisotopicMass": 409.03448727792,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Myu",
    "name": "5-methoxycarbonylmethyl-2-thiouridine monophosphate diradical 2521U",
    "mf": "C12H15N2O9PS",
    "kind": "NucleotideP",
    "oneLetter": "3",
    "ocl": {
      "value": "fmgQH`I^aSbdyZNXOFw`xHbxyDhhilheDiLjmLs`RuUUUSLuLuQDSDHfP@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{WHc|KB_W_Wx@_`@lIr\\SFBrH@h`B_`BH_WxbOrH_P"
    },
    "mass": 394.2945422179627,
    "monoisotopicMass": 394.02358824126003,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Cou",
    "name": "5-carbamoylmethyl-2-thiouridine monophosphate diradical 253U",
    "mf": "C11H14N3O8PS",
    "kind": "NucleotideP",
    "oneLetter": "l",
    "ocl": {
      "value": "fe{pH`I^gBgEIrtXOFw`xHbxyDhhilheDiLjmF\\BVjjjjYfifhbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTC~NKA`"
    },
    "mass": 379.2831638542993,
    "monoisotopicMass": 379.02392259389,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Cau",
    "name": "5-carboxymethyl-2-thiouridine monophosphate diradical 2540U",
    "mf": "C11H13N2O9PS",
    "kind": "NucleotideP",
    "oneLetter": "℘",
    "ocl": {
      "value": "fe{QH`I^aSbdyZNXOFw`xHbxyDhhilheDiLjmF\\BVjjjjYfifhbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTC~NKA`"
    },
    "mass": 380.26792481311594,
    "monoisotopicMass": 380.00793817680005,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Tau",
    "name": "5-taurinomethyl-2-thiouridine monophosphate diradical 254U",
    "mf": "C12H18N3O10PS2",
    "kind": "NucleotideP",
    "oneLetter": "∃",
    "ocl": {
      "value": "fgpj`I^{BgEIrwY{`|[^C`bKblHrIQQSYQJIRYUYIRLxDmUUUTsMSUKTQDqBId@@",
      "coordinates": "!BKAb@tURD@m\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@JH__rH_]^H_P"
    },
    "mass": 459.3892600220213,
    "monoisotopicMass": 459.01712313635005,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 2
    }]
  }, {
    "symbol": "Itu",
    "name": "5-(isopentenylaminomethyl)-2-thiouridine monophosphate diradical 2583U",
    "mf": "C15H22N3O7PS",
    "kind": "NucleotideP",
    "oneLetter": "½",
    "ocl": {
      "value": "fkoqp`I^{BgEIrtGc[p\\DQ\\\\bTTTvTRbTfUVRTYpIZjjjifZfijbHfHQL`@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{W@h`BKB_W_Wx@_`@lIr\\SFBrH@h`B_`BH_Xc|bGvH@gx@bGt"
    },
    "mass": 419.3902285493682,
    "monoisotopicMass": 419.09160823216,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 22
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Mth",
    "name": "5-methyl-2-thiouridine monophosphate diradical 25U",
    "mf": "C10H13N2O7PS",
    "kind": "NucleotideP",
    "oneLetter": "F",
    "ocl": {
      "value": "fncQp`I^aSbdyZCqmxNBHnNQJJJ[JIQJSJlxDmUUUTsMSQDSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
    },
    "mass": 336.25837906774416,
    "monoisotopicMass": 336.01810893766003,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Dmg",
    "name": "N2,7-dimethylguanosine monophosphate diradical 27G",
    "mf": "C12H18N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "∨",
    "ocl": {
      "value": "fmwisBINCt\\J\\TgLp^MoBKbFY}dRbbfrbTRdRUbKN^CWmUUUUKLuUUDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StPAOT`"
    },
    "mass": 375.27487685970397,
    "monoisotopicMass": 375.0943849377,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dma",
    "name": "2,8-dimethyladenosine monophosphate diradical 28A",
    "mf": "C12H16N5O6P",
    "kind": "NucleotideP",
    "oneLetter": "±",
    "ocl": {
      "value": "feghs@INCv\\J\\UdhOFw`eqrIQQSYQJJJQKqLyxK^uUUUPMLAUADSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpP@c`a}_S_|BD}RSuKQ@B\\StP@"
    },
    "mass": 357.2595904272741,
    "monoisotopicMass": 357.08382025367,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mas",
    "name": "2-methyladenosine monophosphate diradical 2A",
    "mf": "C11H14N5O6P",
    "kind": "NucleotideP",
    "oneLetter": "/",
    "ocl": {
      "value": "fi{hs@INBt\\J\\TgHOFwaEqrIQQSYQJIRINIgOAjvjjjjAf@j`bIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtP@gD}D@"
    },
    "mass": 343.2329730224273,
    "monoisotopicMass": 343.06817018921,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Tcy",
    "name": "2-thiocytidine monophosphate diradical 2C",
    "mf": "C9H12N3O6PS",
    "kind": "NucleotideP",
    "oneLetter": "%",
    "ocl": {
      "value": "ff}pp`I^kBgEIrCqmxNBHnNQJJJ[JIQJSMg@ejjjjfYfhbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
    },
    "mass": 321.2470007040807,
    "monoisotopicMass": 321.01844329029,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Nmg",
    "name": "N2-methylguanosine monophosphate diradical 2G",
    "mf": "C11H14N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "L",
    "ocl": {
      "value": "fegis@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\VYspZmjjjjiYfijbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtP@gD}D@SuH"
    },
    "mass": 359.23237794674554,
    "monoisotopicMass": 359.06308480878,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Thu",
    "name": "2-thiouridine monophosphate diradical 2U",
    "mf": "C9H11N2O7PS",
    "kind": "NucleotideP",
    "oneLetter": "2",
    "ocl": {
      "value": "ff}Qp`I^aSbdyjCqmxNBHnNQJJJ[JIQJSMg@ejjjjfYihbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
    },
    "mass": 322.2317616628973,
    "monoisotopicMass": 322.0024588732,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Ahu",
    "name": "3-(3-amino-3-carboxypropyl)-5,6-dihydrouridine monophosphate diradical 308U",
    "mf": "C13H20N3O10P",
    "kind": "NucleotideP",
    "oneLetter": "Ð",
    "ocl": {
      "value": "fkopk@I^gBgENSens`|[^DWGHeEEMeDheIhueMF\\BVjjjjZfijfhbIbDSH@",
      "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}DqbH@gx_c|SFA`lIqOW_Xa}_c~HHa}_c~H@gx@bGt"
    },
    "mass": 409.28630261461393,
    "monoisotopicMass": 409.08863085201,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "App",
    "name": "3-(3-amino-3-carboxypropyl)pseudouridine monophosphate diradical 309U",
    "mf": "C13H18N3O10P",
    "kind": "NucleotideP",
    "oneLetter": "Þ",
    "ocl": {
      "value": "fkopk@OAgBgENSens`|[^DWGHeEEMeDheIhueMF\\BVjjjfZfijfhbIbDSH@",
      "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}DqbH@gx_c|SFA`lIqOW_Xa}_c~HHa}_c~H@gx@bGt"
    },
    "mass": 407.2704211065024,
    "monoisotopicMass": 407.07298078755,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Apu",
    "name": "3-(3-amino-3-carboxypropyl)uridine monophosphate diradical 30U",
    "mf": "C13H18N3O10P",
    "kind": "NucleotideP",
    "oneLetter": "X",
    "ocl": {
      "value": "fkopk@I^gBgENSens`|[^DWGHeEEMeDheIhueMF\\BVjjjjYfijfhbIbDSH@",
      "coordinates": "!BTh|SI~ioOwy`iR\\SiV|SFGxw}FH_]]}DqbH@gx_c|SFA`lIqOW_Xa}_c~HHa}_c~H@gx@bGt"
    },
    "mass": 407.2704211065024,
    "monoisotopicMass": 407.07298078755,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mws",
    "name": "methylwyosine monophosphate diradical 342G",
    "mf": "C15H18N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "∑",
    "ocl": {
      "value": "eghZNL@IG@nahJNEDli`OFspb\\\\bTTTvTRbTbb\\rVSGG`SPrvuUUUUKMTsUUIBDpaBX`@",
      "coordinates": "!B_`CW@mF@ctvDUI|fRxPYgtwP[zV_IorHFY|gD}F@RxPYg|@YgrZOTh{_cuJOS]F@tXAKaI|fw}EMt@"
    },
    "mass": 411.3070845499097,
    "monoisotopicMass": 411.0943849377,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Uhw",
    "name": "undermodified hydroxywybutosine monophosphate diradical 3470G",
    "mf": "C18H23N6O10P",
    "kind": "NucleotideP",
    "oneLetter": "š",
    "ocl": {
      "value": "ejQVEL@IG@nahXJNEDliolRPOFspb\\\\bTTTvTRbTbb\\rVVTttXx|BZFVvjjjjiYjfZjjfjRDIaBDq@@",
      "coordinates": "!BKB^@ceS[H`Yg}ARpAeMtHa}KAcPTh{_S]CjXES[pAeMtH}MtEK@IdnDpBXBbES[UMo@F]ARaERH_X`B_`BH_WxbOq~@Ha}"
    },
    "mass": 514.3839139947949,
    "monoisotopicMass": 514.12132796199,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 18
    }, {
      "symbol": "H",
      "number": 23
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Acw",
    "name": "7-aminocarboxypropylwyosine monophosphate diradical 347G",
    "mf": "C18H23N6O9P",
    "kind": "NucleotideP",
    "oneLetter": "Ω",
    "ocl": {
      "value": "eb^VIL@IG@na`XJNEDlid\\POFspb\\\\bTTTvTRbTbb\\rVRrfcGG`SPrvuUUUUKMTsUUSUIBDpaBX`@",
      "coordinates": "!BDr]RcwwWpAg_tUS[cm~DUAf_XJUTvx}MaEP@_gwWcm~DUDnDUMo|urH@m_@FWwW_]^NwuS[bGtYgx`BbGu~Ox`B_`BH_P"
    },
    "mass": 498.38450907047655,
    "monoisotopicMass": 498.12641334242,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 18
    }, {
      "symbol": "H",
      "number": 23
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hwy",
    "name": "methylated undermodified hydroxywybutosine monophosphate diradical 3480G",
    "mf": "C19H25N6O10P",
    "kind": "NucleotideP",
    "oneLetter": "y",
    "ocl": {
      "value": "efYVEL@IG@nahXJNEDliolRPOFspb\\\\bTTTvTRbTbb\\rVVTttsGG`SPrvuUUUUKMTsUUTuTdHSBDIb@@",
      "coordinates": "!B`HyRtL@f_XbDRxz@UHS_chc|S]BN`MAMwxyKaL@fUHS_cmG_chCjXI|YzfA}bL@fpBYTaHz@F\\BH@gx@upJH@ha}_`CWHc|_`@"
    },
    "mass": 528.4105313996416,
    "monoisotopicMass": 528.1369780264499,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 19
    }, {
      "symbol": "H",
      "number": 25
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hwb",
    "name": "hydroxywybutosine monophosphate diradical 34830G",
    "mf": "C21H27N6O12P",
    "kind": "NucleotideP",
    "oneLetter": "⊆",
    "ocl": {
      "value": "ee[VCL@IG@nahXJNEDliobZV^POFspb\\\\bTTTvTRbTbb\\rVVTtRbfsGG`SPrvuUUUUKMTsUUULuUIBDpaBX`@",
      "coordinates": "!BKB^@ceS[@h`Yg}ARpAeMtHa}KAcPTh{_S]CjXES[pAeMtH}MtEK@IdnDpBXBbES[UMo@F]ARaERH_X`B_`BH_X`B_c~H_]]}bGu~Ox`B_c~H_P"
    },
    "mass": 586.4466945498602,
    "monoisotopicMass": 586.14245733005,
    "unsaturation": 22,
    "elements": [{
      "symbol": "C",
      "number": 21
    }, {
      "symbol": "H",
      "number": 27
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 12
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Pwb",
    "name": "peroxywybutosine monophosphate diradical 34832G",
    "mf": "C21H27N6O13P",
    "kind": "NucleotideP",
    "oneLetter": "W",
    "ocl": {
      "value": "emWVKL@IG@nadXJNEDliohZV^QPOFspb\\\\bTTTvTRbTbb\\rVVTRfTTvXx|BZFVvjjjjiYjfZjjjYjjRDIaBDq@@",
      "coordinates": "!BKB^@ceS[@h`Yg}ARpAeMtHa}KAcPTh{_S]CjXES[pAeMtH}MtEK@IdnDpB[|bES[UMo@F]ARaERH_X`B_`BH_X`Bb@I~Oxa}uwvH_Wxb@I~Oxa}"
    },
    "mass": 602.4460994741785,
    "monoisotopicMass": 602.1373719496199,
    "unsaturation": 22,
    "elements": [{
      "symbol": "C",
      "number": 21
    }, {
      "symbol": "H",
      "number": 27
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 13
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Wyb",
    "name": "wybutosine monophosphate diradical 3483G",
    "mf": "C21H27N6O11P",
    "kind": "NucleotideP",
    "oneLetter": "Y",
    "ocl": {
      "value": "eiSVML@IG@na`XJNEDlilRZVPOFspb\\\\bTTTvTRbTbb\\rVVRbTTvXx|BZFVvjjjjiYjfZjjfZjdaBXPaLP@",
      "coordinates": "!BsJ\\@ciP{@`YWuARPAeMT@a}sNaPThxSUCjhIP{PAeMTD}MTEI@IllDPB[|BIP{eCm@FUARAIPH_Pc|BGtHGzBGtw_Pa}_k|HGzBGt"
    },
    "mass": 570.4472896255419,
    "monoisotopicMass": 570.14754271048,
    "unsaturation": 22,
    "elements": [{
      "symbol": "C",
      "number": 21
    }, {
      "symbol": "H",
      "number": 27
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Awo",
    "name": "7-aminocarboxypropylwyosine methyl ester monophosphate diradical 348G",
    "mf": "C19H25N6O9P",
    "kind": "NucleotideP",
    "oneLetter": "⇑",
    "ocl": {
      "value": "ejQVIL@IG@na`XJNEDlid\\POFspb\\\\bTTTvTRbTbb\\rVVRffXx|BZFVvjjjjiYjfZjjZjRDIaBDq@@",
      "coordinates": "!B`HyRtL@f_XbDRxz@UHS_ch`BS]BN`MAMwxyKaL@fUHS_cmG_chCjXI|YzfA}bL@fpBYTaHz@F\\BHHa}bOq~@Ha}_c~H@ha}"
    },
    "mass": 512.4111264753234,
    "monoisotopicMass": 512.14206340688,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 19
    }, {
      "symbol": "H",
      "number": 25
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Wyo",
    "name": "wyosine monophosphate diradical 34G",
    "mf": "C14H16N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "€",
    "ocl": {
      "value": "ek`ZNL@IG@nahJNEDli`OFspb\\\\bTTTvTRbTbb\\rVXx|BZFVvjjjjiYjfZjdaBXPaLP@",
      "coordinates": "!B_`CWMF@ctvDUI|fRxPYgtwP[zV_IorHFY|gD}F@RxPYg|@YgrZOTh{_cuJOS]F@tXAKaI|fw}D"
    },
    "mass": 397.2804671450629,
    "monoisotopicMass": 397.07873487324,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 14
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Pdu",
    "name": "3-methylpseudouridine monophosphate diradical 39U",
    "mf": "C10H13N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "κ",
    "ocl": {
      "value": "fncPK@OAaSbgIrtGc[pbxyDhhilheDiMFs`RuUUTsTuMDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@HoWtw@`lFC~NSU@"
    },
    "mass": 320.1929965859354,
    "monoisotopicMass": 320.04095238282997,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mri",
    "name": "3-methyluridine monophosphate diradical 3U",
    "mf": "C10H13N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "δ",
    "ocl": {
      "value": "fncPK@I^aSbgIrtGc[pbxyDhhilheDiMFs`RuUUUSLuMDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@HoWtw@`lFC~NSU@"
    },
    "mass": 320.1929965859354,
    "monoisotopicMass": 320.04095238282997,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Acc",
    "name": "N4-acetylcytidine monophosphate diradical 42C",
    "mf": "C11H14N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "M",
    "ocl": {
      "value": "fikpK@I^kBgENSghOFwaEqrIQQSYQJIRYiQg@ejjjjfYffhbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuPOxxSItuP"
    },
    "mass": 347.21837644817225,
    "monoisotopicMass": 347.05185141949,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Iws",
    "name": "isowyosine monophosphate diradical 42G",
    "mf": "C14H16N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "⊇",
    "ocl": {
      "value": "ek`ZNL@IG@fnhJNEDla`OFspb\\\\bTTTvTRbTbSbRrXx|BjzfVjjjjiYjYjjdaBXPaLP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RStwQ@MD@RpQ_qcQSU@"
    },
    "mass": 397.2804671450629,
    "monoisotopicMass": 397.07873487324,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 14
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dmc",
    "name": "N4,N4-dimethylcytidine monophosphate diradical 44C",
    "mf": "C11H16N3O7P",
    "kind": "NucleotideP",
    "oneLetter": "μ",
    "ocl": {
      "value": "fasqs@I^kBgENSdGc[pbxyDhhilheDiLuF\\BVjjjjYfZjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBGpcbpXBGtSItuPSU@H_Wtw@`lFDuPOxxlF@"
    },
    "mass": 333.23485303196554,
    "monoisotopicMass": 333.07258686438,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Adw",
    "name": "7-aminocarboxypropyl-demethylwyosine monophosphate diradical 47G",
    "mf": "C17H21N6O9P",
    "kind": "NucleotideP",
    "oneLetter": "¥",
    "ocl": {
      "value": "elVVIL@IG@fnohJNEDlahTPOFspb\\\\bTTTvTRbTbSbRrrTtXx|BjzfVjjjjiYjYjjijdaBXPaLP@",
      "coordinates": "!B`MERc|@Y_]^DUH{_UMo_tXa}SXPTh{_w}GjXES[pAg_t]F@cm@Il@f@haTvuS[pAgPThQTbGvH@ha}_c~HGx@bGt"
    },
    "mass": 484.3578916656298,
    "monoisotopicMass": 484.1107632779601,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 17
    }, {
      "symbol": "H",
      "number": 21
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ncd",
    "name": "N4-methylcytidine monophosphate diradical 4C",
    "mf": "C10H14N3O7P",
    "kind": "NucleotideP",
    "oneLetter": "ν",
    "ocl": {
      "value": "fncqs@I^kBgENSdGc[pbxyDhhilheDiLts`RuUUUSLsUDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuPKA`"
    },
    "mass": 319.2082356271187,
    "monoisotopicMass": 319.05693679992004,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dmw",
    "name": "4-demethylwyosine monophosphate diradical 4G",
    "mf": "C13H14N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "†",
    "ocl": {
      "value": "fcis@INBwlJ\\TgHp^MoBKcdRbbfrbTRdR\\RVYspZ}fnjjjjefifjiHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RStwQ@MD@RpQ_qcQ"
    },
    "mass": 383.253849740216,
    "monoisotopicMass": 383.06308480878,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mtu",
    "name": "5-methoxyuridine monophosphate diradical 501U",
    "mf": "C10H13N2O9P",
    "kind": "NucleotideP",
    "oneLetter": "5",
    "ocl": {
      "value": "fasQK@I^aSbgIsUhOFwaEqrIQQSYQJIRYULxDmUUUTsMSTQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
    },
    "mass": 336.19240151025366,
    "monoisotopicMass": 336.03586700240004,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Uoa",
    "name": "uridine 5-oxyacetic acid monophosphate diradical 502U",
    "mf": "C11H13N2O11P",
    "kind": "NucleotideP",
    "oneLetter": "V",
    "ocl": {
      "value": "fmgQk@I^aSbgIsUlu`|[^DWGHeEEMeDheIeUeF\\BVjjjjYfiijHbXaDr@@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{WHc|KB_W_Wx@_`@lIr\\SFBrHHc|_`BH_Xc|_`BH_P"
    },
    "mass": 380.2019472556255,
    "monoisotopicMass": 380.02569624154,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ume",
    "name": "uridine 5-oxyacetic acid methyl ester monophosphate diradical 503U",
    "mf": "C12H15N2O11P",
    "kind": "NucleotideP",
    "oneLetter": "υ",
    "ocl": {
      "value": "fcwQk@I^aSbgIsUlu`|[^DWGHeEEMeDheIeUeLs`RuUUUSLuMMTQDqBId@@",
      "coordinates": "!BKAb@tURDM\\YpMAMpBYMcxc|KB]~@Ha}SXWHc|bOqMcx}RtDvH_Xa}bOrH@ha}_c~HHa}"
    },
    "mass": 394.2285646604723,
    "monoisotopicMass": 394.041346306,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hxc",
    "name": "5-hydroxycytidine monophosphate diradical 50C",
    "mf": "C9H12N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "Ç",
    "ocl": {
      "value": "fncpK@I^[BgENSfhOFwaEqrIQQSYQJIRYUg@ejjjjfYfjHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
    },
    "mass": 321.1810231465902,
    "monoisotopicMass": 321.03620135502996,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hxu",
    "name": "5-hydroxyuridine monophosphate diradical 50U",
    "mf": "C9H11N2O9P",
    "kind": "NucleotideP",
    "oneLetter": "∝",
    "ocl": {
      "value": "fncQK@I^aSbgIsUhOFwaEqrIQQSYQJIRYUg@ejjjjfYjZHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
    },
    "mass": 322.1657841054069,
    "monoisotopicMass": 322.02021693794,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Amu",
    "name": "5-aminomethyluridine monophosphate diradical 510U",
    "mf": "C10H14N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "∪",
    "ocl": {
      "value": "faspK@I^{BgENSehOFwaEqrIQQSYQJIRYULxDmUUUTsMSTQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
    },
    "mass": 335.207640551437,
    "monoisotopicMass": 335.05185141949,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mau",
    "name": "5-methylaminomethyluridine monophosphate diradical 511U",
    "mf": "C11H16N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "{",
    "ocl": {
      "value": "fikpK@I^{BgENSehOFwaEqrIQQSYQJIRYUYg@ejjjjfYjZhbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTBpX"
    },
    "mass": 349.2342579562838,
    "monoisotopicMass": 349.06750148395,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hmc",
    "name": "5-hydroxymethylcytidine monophosphate diradical 51C",
    "mf": "C10H14N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "∅",
    "ocl": {
      "value": "faspK@I^[BgENSghOFwaEqrIQQSYQJIRYULxDmUUUTsLuTQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
    },
    "mass": 335.207640551437,
    "monoisotopicMass": 335.05185141949,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Cur",
    "name": "5-carboxymethylaminomethyluridine monophosphate diradical 51U",
    "mf": "C12H16N3O10P",
    "kind": "NucleotideP",
    "oneLetter": "!",
    "ocl": {
      "value": "fcwpk@I^{BgENSej}`|[^DWGHeEEMeDheIeUdhs`RuUUUSLuMSTQDqBId@@",
      "coordinates": "!BKAb@tURDM\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@I~@Ha}"
    },
    "mass": 393.24380370165557,
    "monoisotopicMass": 393.05733072309,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Chr",
    "name": "5-carboxyhydroxymethyluridine monophosphate diradical 520U",
    "mf": "C11H13N2O11P",
    "kind": "NucleotideP",
    "oneLetter": "≥",
    "ocl": {
      "value": "fmgQk@I^aSbgIrwlu`|[^DWGHeEEMeDheIeUCF\\BVjjjjYfiijHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tTuPOxxlF@"
    },
    "mass": 380.2019472556255,
    "monoisotopicMass": 380.02569624154,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mcu",
    "name": "5-methoxycarbonylmethyluridine monophosphate diradical 521U",
    "mf": "C12H15N2O10P",
    "kind": "NucleotideP",
    "oneLetter": "1",
    "ocl": {
      "value": "fmgPk@I^aSbgIrt\\p^MoBKcdRbbfrbTRdrjtsNAKUUUULsTsUDQLPbY@@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{WHc|KB_W_Wx@_`@lIr\\SFBrH@h`B_`BH_WxbOrH_P"
    },
    "mass": 378.229159736154,
    "monoisotopicMass": 378.04643168643,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hme",
    "name": "5-(carboxyhydroxymethyl)uridine methyl ester monophosphate diradical 522U",
    "mf": "C12H15N2O11P",
    "kind": "NucleotideP",
    "oneLetter": ",",
    "ocl": {
      "value": "fcwQk@I^aSbgIrwlu`|[^DWGHeEEMeDheIeUCLs`RuUUUSLuMMTQDqBId@@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{WHc|KB_W_Wx@_`@lIr\\SFBrHHc|_`A~@Ha}_c~H@ha}"
    },
    "mass": 394.2285646604723,
    "monoisotopicMass": 394.041346306,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Cxu",
    "name": "5-carboxymethyluridine monophosphate diradical 52U",
    "mf": "C11H13N2O10P",
    "kind": "NucleotideP",
    "oneLetter": "◊",
    "ocl": {
      "value": "fe{Pk@I^aSbgIrt\\p^MoBKcdRbbfrbTRdrjtYpIZjjjifZfZbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTC~NKA`"
    },
    "mass": 364.2025423313072,
    "monoisotopicMass": 364.03078162197,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hmu",
    "name": "5-carbamoylhydroxymethyluridine monophosphate diradical 531U",
    "mf": "C11H14N3O10P",
    "kind": "NucleotideP",
    "oneLetter": "r",
    "ocl": {
      "value": "fmgpk@I^WBgENSeoY`|[^DWGHeEEMeDheIeUCF\\BVjjjjYfiijHbXaDr@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tTuPOxxlF@"
    },
    "mass": 379.21718629680873,
    "monoisotopicMass": 379.04168065863,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ymu",
    "name": "5-carbamoylmethyluridine monophosphate diradical 53U",
    "mf": "C11H14N3O9P",
    "kind": "NucleotideP",
    "oneLetter": "&",
    "ocl": {
      "value": "fe{qK@I^gBgENSehp^MoBKcdRbbfrbTRdrjtYpIZjjjifZfZbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSUAMTC~NKA`"
    },
    "mass": 363.2177813724905,
    "monoisotopicMass": 363.04676603906006,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ttu",
    "name": "5-taurinomethyluridine monophosphate diradical 54U",
    "mf": "C12H18N3O11PS",
    "kind": "NucleotideP",
    "oneLetter": "Ê",
    "ocl": {
      "value": "fgqh`I^{BgENSenswAxv|HnJpcHeEEMeDheIeUdeHs`RuUUUSLuMTmQDSDHfP@",
      "coordinates": "!BKAb@tURD@m\\YpMAMpBYMcx`BKB]~@Ha}SXW@h`Bb@IMcx}RtDvH_Xa}b@JH@ha}b@JH__rH_]^H_P"
    },
    "mass": 443.32387754021244,
    "monoisotopicMass": 443.03996658152005,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Cmu",
    "name": "5-cyanomethyluridine monophosphate diradical 55U",
    "mf": "C11H12N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "Ѷ",
    "ocl": {
      "value": "fikpK@I^GBgENSehOFwaEqrIQQSYQJIRYUYg@ejjjjfYj[hbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tPCQ"
    },
    "mass": 345.20249494006066,
    "monoisotopicMass": 345.03620135502996,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Pyu",
    "name": "5-(isopentenylaminomethyl)uridine monophosphate diradical 583U",
    "mf": "C15H22N3O8P",
    "kind": "NucleotideP",
    "oneLetter": "¾",
    "ocl": {
      "value": "fkopK@I^{BgENSehOFwaEqrIQQSYQJIRYUYIQg@ejjjjfYjZfjHbXaDr@@",
      "coordinates": "!BS]@lFJU`@Gyoza`lzf@lIwx@`H{W@h`BKB_W_Wx@_`@lIr\\SFBrH@h`B_`BH_Xc|bGvH@gx@bGt"
    },
    "mass": 403.32484606755946,
    "monoisotopicMass": 403.11445167733,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 22
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mdu",
    "name": "5-methyldihydrouridine monophosphate diradical 58U",
    "mf": "C10H15N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "ρ",
    "ocl": {
      "value": "fncPK@I^aSbgIrtGc[pbxyDhhilheDiLjs`RuUUUSTuMDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
    },
    "mass": 322.20887809404695,
    "monoisotopicMass": 322.05660244729,
    "unsaturation": 8,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mcd",
    "name": "5-methylcytidine monophosphate diradical 5C",
    "mf": "C10H14N3O7P",
    "kind": "NucleotideP",
    "oneLetter": "?",
    "ocl": {
      "value": "fncqs@I^[BgENSdGc[pbxyDhhilheDiLjs`RuUUUSLsUDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@"
    },
    "mass": 319.2082356271187,
    "monoisotopicMass": 319.05693679992004,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hia",
    "name": "N6-(cis-hydroxyisopentenyl)adenosine monophosphate diradical 60A",
    "mf": "C15H20N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "`",
    "ocl": {
      "value": "eg`ZNL@IG@fnhJNEDlk`OFspb\\\\bTTTvTRbTbSVRTSGG`USUUUUTCLATuTDHSBDIbPSH",
      "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@b@JH@ha}bOrH_Wxb@JH_P"
    },
    "mass": 413.3229660580212,
    "monoisotopicMass": 413.11003500216003,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 20
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mta",
    "name": "2-methylthio-N6-methyladenosine monophosphate diradical 621A",
    "mf": "C12H16N5O6PS",
    "kind": "NucleotideP",
    "oneLetter": "∞",
    "ocl": {
      "value": "fmwhp`CQstZLDxipEfGa[qZDYEIlheDdhXdmDmKR\\u{MUUUU@aEUAFPTdmH@",
      "coordinates": "!BBGw|B@a}_S\\H@a}TEJNOuP{Ntm@fPBN[~iRSpHUCneXDBYTEITAEPDiVA@fTBYU@Sj[p"
    },
    "mass": 389.3243778334011,
    "monoisotopicMass": 389.05589142807,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Tca",
    "name": "N6-threonylcarbamoyladenosine monophosphate diradical 62A",
    "mf": "C15H19N6O10P",
    "kind": "NucleotideP",
    "oneLetter": "6",
    "ocl": {
      "value": "edRVEL@IG@fnehJNEDligo`POFspb\\\\bTTTvTRbTbSVTrbbcGG`USUUUUTCLASUMUABDpaBX`@",
      "coordinates": "!BzfC@IeKPaDn}bHCQbOsQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@b@JH@ha}_c~H@ha}_c~H@ha}uwu~@Ha}"
    },
    "mass": 474.31994328836606,
    "monoisotopicMass": 474.09002783307,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 19
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hva",
    "name": "N6-hydroxynorvalylcarbamoyladenosine monophosphate diradical 63A",
    "mf": "C16H21N6O10P",
    "kind": "NucleotideP",
    "oneLetter": "√",
    "ocl": {
      "value": "elZVIB@IG@fnehJNDligo`POEQql|HgGHeEEMeDheHdueLhhiVNO@jfjjjjhFXBfjZj`aBXPaLP@",
      "coordinates": "!BpBYTvxBNFY|bEJObGvOS\\@Yt]~DUEJOctu~@Ha}`HzOSTwPTh~HH`BbGvH_Xc|_`BH_Xc|_`BH_]_|bOq~Oxc|bGt"
    },
    "mass": 488.34656069321284,
    "monoisotopicMass": 488.10567789753003,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 16
    }, {
      "symbol": "H",
      "number": 21
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Aya",
    "name": "N6-acetyladenosine monophosphate diradical 64A",
    "mf": "C12H14N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "⇓",
    "ocl": {
      "value": "fmwis@INBwlJ\\TgLp^MoBKcdRbbfrbTRdRZrcN^CUmUUUTCLASTDQLPbY@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}RIqOQ@@"
    },
    "mass": 371.2431138434808,
    "monoisotopicMass": 371.06308480878,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Gca",
    "name": "N6-glycinylcarbamoyladenosine monophosphate diradical 65A",
    "mf": "C13H15N6O9P",
    "kind": "NucleotideP",
    "oneLetter": "≡",
    "ocl": {
      "value": "eohVIL@IG@fnehJNEDlikg`OFspb\\\\bTTTvTRbTbSVTrTXx|BjZjjjj`Y`JZfhHPfDHSD@@",
      "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@bOrHHa}_c~H@ha}bOq~@Ha}"
    },
    "mass": 430.2673035543541,
    "monoisotopicMass": 430.06381308458,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 13
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Tya",
    "name": "N6-methyl-N6-threonylcarbamoyladenosinemonophosphate diradical 662A",
    "mf": "C16H21N6O10P",
    "kind": "NucleotideP",
    "oneLetter": "E",
    "ocl": {
      "value": "elZVEL@IG@fnmhJNEDleo`XPOFspb\\\\bTTTvTRbTbSVbaTTTXx|BjZjjjj`Y`JfjZjBDIaBDq@@",
      "coordinates": "!BzfC@IeKPaDn}bHCQb@KQwuRDFALYpHCQt]W@h`BTmCQw}~N`ME~@Gx@bOrHHa}_`A~Ox`BbGu~Ox`BbGwW_Wx@bGt"
    },
    "mass": 488.34656069321284,
    "monoisotopicMass": 488.10567789753003,
    "unsaturation": 18,
    "elements": [{
      "symbol": "C",
      "number": 16
    }, {
      "symbol": "H",
      "number": 21
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Nna",
    "name": "N6,N6-dimethyladenosine monophosphate diradical 66A",
    "mf": "C12H16N5O6P",
    "kind": "NucleotideP",
    "oneLetter": "ζ",
    "ocl": {
      "value": "feghs@INBwlJ\\TgHOFwaEqrIQQSYQJIRIMZLyxMVuUUUPLpEUADSDHfP@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}RFBp"
    },
    "mass": 357.2595904272741,
    "monoisotopicMass": 357.08382025367,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Fya",
    "name": "N6-formyladenosine monophosphate diradical 67A",
    "mf": "C11H12N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "Ϩ",
    "ocl": {
      "value": "fegis@INBwlJ\\TgLp^MoBKcdRbbfrbTRdRZrYspZmjjjj`Y`JZBHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}RtP@"
    },
    "mass": 357.216496438634,
    "monoisotopicMass": 357.04743474432,
    "unsaturation": 16,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Hma",
    "name": "N6-hydroxymethyladenosine monophosphate diradical 68A",
    "mf": "C11H14N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "Ϫ",
    "ocl": {
      "value": "fegis@INBwlJ\\TgLp^MoBKcdRbbfrbTRdRZrYspZmjjjj`Y`JjBHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@D}RtP@"
    },
    "mass": 359.23237794674554,
    "monoisotopicMass": 359.06308480878,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Cca",
    "name": "cyclic N6-threonylcarbamoyladenosine monophosphate diradical 69A",
    "mf": "C15H17N6O9P",
    "kind": "NucleotideP",
    "oneLetter": "e",
    "ocl": {
      "value": "ehRVIL@IG@fnehJNEDliko`OFspb\\\\bTTTvTRbTbSVTRRtXx|BjZvNjjjj`Y`IjfjbHPfDHSD`z`",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_IorHbGtgD}F@RxRH_WwW@hbOTh}RtXCQ`A`l_`A`iVCjKAcjX@A~@h`Bup"
    },
    "mass": 456.30465685593623,
    "monoisotopicMass": 456.07946314904,
    "unsaturation": 20,
    "elements": [{
      "symbol": "C",
      "number": 15
    }, {
      "symbol": "H",
      "number": 17
    }, {
      "symbol": "N",
      "number": 6
    }, {
      "symbol": "O",
      "number": 9
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Fcy",
    "name": "5-formylcytidine monophosphate diradical71C",
    "mf": "C10H12N3O8P",
    "kind": "NucleotideP",
    "oneLetter": ">",
    "ocl": {
      "value": "faspK@I^[BgENSghOFwaEqrIQQSYQJIRYULxDmUUUTsLttQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFBpXSU@@tP"
    },
    "mass": 333.1917590433254,
    "monoisotopicMass": 333.03620135502996,
    "unsaturation": 12,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 12
    }, {
      "symbol": "N",
      "number": 3
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Tur",
    "name": "4-thiouridine monophosphate diradical 74U",
    "mf": "C9H11N2O7PS",
    "kind": "NucleotideP",
    "oneLetter": "4",
    "ocl": {
      "value": "ff}Qp`I^aSbgIrCqmxQ\\ZaFQJJJ[JIQJSMg@ejjjjfYihbIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
    },
    "mass": 322.2317616628973,
    "monoisotopicMass": 322.0024588732,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Meg",
    "name": "7-methylguanosine monophosphate diradical 7G",
    "mf": "C11H15N5O7P",
    "kind": "NucleotideP",
    "oneLetter": "7",
    "ocl": {
      "value": "fegisDINCt\\J\\TgLp^MoBKbF\\bTTTvTRbTbRlSN^CWmUUUUKLuSTQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RqdCQ@B\\StP@"
    },
    "mass": 360.2403187008013,
    "monoisotopicMass": 360.07090984101,
    "unsaturation": 13,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mea",
    "name": "8-methyladenosine monophosphate diradical 8A",
    "mf": "C11H14N5O6P",
    "kind": "NucleotideP",
    "oneLetter": "â",
    "ocl": {
      "value": "fi{hs@INCt\\J\\UdhOFw`eqrIQQSYQJJJQKigOA[vjjjjAi`J`bIbDSH@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpP@c`a}_S_|BD}RSuKQ@MD@"
    },
    "mass": 343.2329730224273,
    "monoisotopicMass": 343.06817018921,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 14
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 6
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Dhu",
    "name": "dihydrouridine monophosphate diradical 8U",
    "mf": "C9H13N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "D",
    "ocl": {
      "value": "ff}PK@I^aSbgIsTGc[pbxyDhhilheDiLv\\BVjjjjZffbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
    },
    "mass": 308.1822606892002,
    "monoisotopicMass": 308.04095238282997,
    "unsaturation": 8,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Ins",
    "name": "inosine monophosphate diradical 9A",
    "mf": "C10H11N4O7P",
    "kind": "NucleotideP",
    "oneLetter": "I",
    "ocl": {
      "value": "fakIs@INBvENJSghOFwaEqrIQQSYQJIRIMLyxMVuUUUTlsSTQDqBId@@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOq_qopHBGtgD}D@RpPH_Wtw@aOTd}RtPCQ@@"
    },
    "mass": 330.1911165763972,
    "monoisotopicMass": 330.03653570766,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 4
    }, {
      "symbol": "O",
      "number": 7
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Pis",
    "name": "pseudouridine monophosphate diradical 9U",
    "mf": "C9H11N2O8P",
    "kind": "NucleotideP",
    "oneLetter": "P",
    "ocl": {
      "value": "ff}PK@OAaSbgIsTGc[pbxyDhhilheDiLv\\BVjjjfZffbHfHQL`@",
      "coordinates": "!BNuSFPDlDTEHt_pHtP@H_TuPBOpcbpXBGtSItuPSU@H_Wtw@`lFDuP"
    },
    "mass": 306.1663791810886,
    "monoisotopicMass": 306.02530231837,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 9
    }, {
      "symbol": "H",
      "number": 11
    }, {
      "symbol": "N",
      "number": 2
    }, {
      "symbol": "O",
      "number": 8
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Pqb",
    "name": "preQ0base 100G diradical (base)",
    "mf": "C7H5N5O",
    "kind": "Nucleotide",
    "oneLetter": "ψ",
    "ocl": {
      "value": "dk^h@DxYLLbbTTRekiujYj^`@",
      "coordinates": "!B|Gwp_Gy|Gwp_[lk_gp_Ag_wrYRs}|f"
    },
    "mass": 175.1477760289729,
    "monoisotopicMass": 175.04940980287,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 5
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Pqg",
    "name": "preQ1base 101G diradical (base)",
    "mf": "C7H9N5O",
    "kind": "Nucleotide",
    "oneLetter": "∇",
    "ocl": {
      "value": "dk^h@DxYLLbbTTRckiUjYij`@",
      "coordinates": "!BWyfe[tlDWye_fXx@RpRe[wtHSuHH@a}"
    },
    "mass": 179.179539045196,
    "monoisotopicMass": 179.08070993179,
    "unsaturation": 10,
    "elements": [{
      "symbol": "C",
      "number": 7
    }, {
      "symbol": "H",
      "number": 9
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 1
    }]
  }, {
    "symbol": "Qba",
    "name": "Qbase 10G diradical (base)",
    "mf": "C12H15N5O3",
    "kind": "Nucleotide",
    "oneLetter": "∴",
    "ocl": {
      "value": "fbmi`@D\\EHpHyrJIQQJMJIPtyIPTmSMMUMUP@@",
      "coordinates": "!BRpQ_f^i`RpQKAEARzfA_f_pHtP@H_Pc|BGuPThxUCl{RtBYTd|"
    },
    "mass": 277.27967290184347,
    "monoisotopicMass": 277.11748936431,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 15
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 3
    }]
  }, {
    "symbol": "Dgc",
    "name": "N2,7-dimethylguanosine cap (cap DMG) diradical 279553N",
    "mf": "C12H18N5O11P2",
    "kind": "Nucleotide",
    "oneLetter": "®",
    "ocl": {
      "value": "e`TZMBHIG@aihJNEHdlemck`OFspz|OgDJ\\bTTTvTRbTbRvbtfKGG`UPuUUUUJtuTmUTPaLHPfH@@",
      "coordinates": "!BvuPfpDnDtEK_t_rHtXBH_TwPbOr_IorHbGtgD}F@RxS|uxc|_]^OTh}RIlBH_]F@IqOQ`@A~_c|bH}RbGt"
    },
    "mass": 470.24625855539705,
    "monoisotopicMass": 470.04780541440005,
    "unsaturation": 13,
    "elements": [{
      "symbol": "C",
      "number": 12
    }, {
      "symbol": "H",
      "number": 18
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Dpa",
    "name": "5′-(3′-dephosphoacetyl-CoA) diradical 4155N",
    "mf": "C23H35N7O16P3S",
    "kind": "Nucleotide",
    "oneLetter": "♣",
    "ocl": {
      "value": "elz~@jDCHlemnSTLBAEKBjfckgbV]XpEfCpB|IoCtHZy{lbdvbbfrbTRdRNRdnTbefRTrRTdTRrFVfjjjj`V`bZjjfjZjZ`bbLSaRP@",
      "coordinates": "!BvtmKaMmKUMlfgto[tDw_cosWt]~H@dvObGv_F_sWbOpgKMG_R}m}bHa}HbOSX}M_cQw}G_OwzH_[wW_c~H_Wx@G{|bM]}bGvHGxbGu~Oxa}bOq~Oxa}_c~H_WxuwvH_P"
    },
    "mass": 790.5483266874629,
    "monoisotopicMass": 790.1073852418399,
    "unsaturation": 21,
    "elements": [{
      "symbol": "C",
      "number": 23
    }, {
      "symbol": "H",
      "number": 35
    }, {
      "symbol": "N",
      "number": 7
    }, {
      "symbol": "O",
      "number": 16
    }, {
      "symbol": "P",
      "number": 3
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Dpm",
    "name": "5′-(3′-dephosphomalonyl-CoA) diradical 4255N",
    "mf": "C24H35N7O18P3S",
    "kind": "Nucleotide",
    "oneLetter": "♥",
    "ocl": {
      "value": "efq~DjDCHlemnSTLBAEKBjfckgbV]XrzpEfCpB|IoCtHZy{lbdvbbfrbTRdRNRdnTbefRTrRTrdbbVPrtuUUUTBtDSUUTuSUSSTDTQb\\JR@@",
      "coordinates": "!BIlB_Ib[@pAe`zni`FALSF@A~FBq~OrpXbGveX@A~_c~OTa`lzf@_ha}_]_Q`MF@bOpXKA`loXbH__rHb@JHoX`B@m]}uwx@bGu~Ox`BbKvH@ha}_c~H@hb}b@JH_Xc|_`BH_X`B_`BHoP"
    },
    "mass": 834.5578724328346,
    "monoisotopicMass": 834.0972144809799,
    "unsaturation": 23,
    "elements": [{
      "symbol": "C",
      "number": 24
    }, {
      "symbol": "H",
      "number": 35
    }, {
      "symbol": "N",
      "number": 7
    }, {
      "symbol": "O",
      "number": 18
    }, {
      "symbol": "P",
      "number": 3
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Dsc",
    "name": "5′-(3′-dephosphosuccinyl-CoA) radical 4355N",
    "mf": "C25H37N7O18P3S",
    "kind": "Nucleotide",
    "oneLetter": "♦",
    "ocl": {
      "value": "eny~DjDCHlemnSTLBAEKBjfckgbV]XzvpOFCpB|IoCtHZy{lbdvbbfrbTRdRNRdnTbefRTrRTrTdTRrFVfjjjj`V`bZjjfjZjZfhHhcDxTd@@",
      "coordinates": "!B[~kjXFjiV[Ry|fcm}MtGwWctvH_]Q_c}KaGwWbGvN`H}MgrX@_gx@h`gKB\\lbGvOSX}M@m^H@gwWbGvH@ha}_Xc|bGxb@I~@Ha}b@JH_X`B_`BH_X`BbGvH@ha}_c~H@ha}b@I~@Ha}"
    },
    "mass": 848.5844898376815,
    "monoisotopicMass": 848.11286454544,
    "unsaturation": 23,
    "elements": [{
      "symbol": "C",
      "number": 25
    }, {
      "symbol": "H",
      "number": 37
    }, {
      "symbol": "N",
      "number": 7
    }, {
      "symbol": "O",
      "number": 18
    }, {
      "symbol": "P",
      "number": 3
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Dpc",
    "name": "5′-(3′-dephospho-CoA) radical 455N",
    "mf": "C21H32N7O13P2S",
    "kind": "Nucleotide",
    "oneLetter": "♠",
    "ocl": {
      "value": "ek_^KBDIG@nabYXJNEHdliemh\\QPEfspZ|CPcKmnrIQQSYQJIRIGIRWJQRsIJYIccpJkjjjjjAZBIjjjZijjBDIaBDq@@",
      "coordinates": "!B[zW[UI|YchAMc{vHcuJH@m~NbGuKvwvHb@JNwx}Rgqe}bHa}@h`gDr\\Sb@JOTh}R@m]~@@A~b@I~@H`B_X`_hb}_`CW@h`B_`BH@gx@upJH@gx@b@I~@@"
    },
    "mass": 684.5310558604504,
    "monoisotopicMass": 684.1254042880199,
    "unsaturation": 19,
    "elements": [{
      "symbol": "C",
      "number": 21
    }, {
      "symbol": "H",
      "number": 32
    }, {
      "symbol": "N",
      "number": 7
    }, {
      "symbol": "O",
      "number": 13
    }, {
      "symbol": "P",
      "number": 2
    }, {
      "symbol": "S",
      "number": 1
    }]
  }, {
    "symbol": "Dpe",
    "name": "5′-diphosphate end 552N",
    "mf": "O3P",
    "kind": "Nucleotide",
    "oneLetter": "ϒ",
    "ocl": {
      "value": "gJQdebGF^Dx|duK@@",
      "coordinates": "!BbOq~@GxbGt"
    },
    "mass": 78.97197677137483,
    "monoisotopicMass": 78.95850585713,
    "unsaturation": 1,
    "elements": [{
      "symbol": "O",
      "number": 3
    }, {
      "symbol": "P",
      "number": 1
    }]
  }, {
    "symbol": "Mgc",
    "name": "7-methylguanosine cap (cap 0) diradical 79553N",
    "mf": "C11H16N5O11P2",
    "kind": "Nucleotide",
    "oneLetter": "©",
    "ocl": {
      "value": "eohZMBHIG@aihJNEHdlemck`OFspz|GgDJ\\bTTTvTRbTbRvbtcXx|BjFjjjjiVfjejjHPfDHSD@@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_I`JHbGtgD}F@RxPBux`B_]^OTh}RIlBH_]F@IqOQ`@A~_c|BbHa}"
    },
    "mass": 456.2196411505502,
    "monoisotopicMass": 456.03215534994,
    "unsaturation": 13,
    "elements": [{
      "symbol": "C",
      "number": 11
    }, {
      "symbol": "H",
      "number": 16
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 11
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Gyy",
    "name": "guanylylated 5′ end (cap G) diradical 9553N",
    "mf": "C10H13N5O10P2",
    "kind": "Nucleotide",
    "oneLetter": "ϑ",
    "ocl": {
      "value": "fkhh`INCt\\J\\UENY{NCqmxM|EnNQJJJ[JIQJQHzIRLyxM^uUUUTkSULuQDSDHfP@",
      "coordinates": "!BvuPfpDnDtEK_tPJHtXBH_TwPb@J_I`JHbGtgD}F@RxPBux`B_]^OTh}R_`CQ`B\\StXA~@C}~@Gx"
    },
    "mass": 425.1856780673293,
    "monoisotopicMass": 425.01376563368,
    "unsaturation": 14,
    "elements": [{
      "symbol": "C",
      "number": 10
    }, {
      "symbol": "H",
      "number": 13
    }, {
      "symbol": "N",
      "number": 5
    }, {
      "symbol": "O",
      "number": 10
    }, {
      "symbol": "P",
      "number": 2
    }]
  }, {
    "symbol": "Furp",
    "name": "furan phosphate radical",
    "mf": "C5H6O4P",
    "kind": "RNAp",
    "oneLetter": "⬠",
    "ocl": {
      "value": "dmtBPDpnAYcpRZ}eeYjii@@",
      "coordinates": "!B]w|Mw\\B_S]wW\\BtP@oKS~frpP"
    },
    "mass": 161.072705703704,
    "monoisotopicMass": 161.00037067008,
    "unsaturation": 5,
    "elements": [{
      "symbol": "C",
      "number": 5
    }, {
      "symbol": "H",
      "number": 6
    }, {
      "symbol": "O",
      "number": 4
    }, {
      "symbol": "P",
      "number": 1
    }]
  }];

  /**
   * Recreate a one letter sequence
   * @param {} mf
   */


  function groupsToSequence$2(mf) {
    mf = mf.replace(/\([^(]*\)/g, '');
    let parts = mf.split(/(?=[A-Z ])/);
    let usefulParts = [];

    for (let part of parts) {
      if (part === ' ') {
        usefulParts.push(' ');
        continue;
      }

      if (!part.match(/^[A-Z][a-z]{2,6}/)) continue;

      if (groupsObject[part] && groupsObject[part].oneLetter) {
        usefulParts.push(groupsObject[part].oneLetter);
      } else {
        usefulParts.push('?');
      }
    }

    return usefulParts.join('').replace(/ +/g, ' ').trim();
  }

  var groupsToSequence_1 = groupsToSequence$2;

  function getGroupsObject() {
    let object = {};
    groups$2.forEach(e => {
      object[e.symbol] = e;
    });
    return object;
  }

  var src$b = {
    groups: groups$2,
    getGroupsObject,
    groupsToSequence: groupsToSequence_1
  };

  function allowNeutralLoss(mf, options) {
    if (Array.isArray(mf)) {
      for (let i = 0; i < mf.length; i++) {
        mf[i] = allowOneNeutralLoss(mf[i]);
      }

      return mf;
    } else {
      return allowOneNeutralLoss(mf);
    }
  }

  function allowOneNeutralLoss(mf) {
    mf = mf.replace(/(Ser|Thr|Asp|Glu)(?!\()/g, '$1(H-2O-1)0-1');
    mf = mf.replace(/(Arg|Lys|Asn|Gln)(?!\()/g, '$1(N-1H-3)0-1');
    return mf;
  }

  var allowNeutralLoss_1$1 = allowNeutralLoss;

  // Link for UTF8 code for modified: https://codepoints.net/search?sc=Grek

  var aminoAcids = [// Standard amino acids
  {
    name: 'Alanine',
    aa3: 'Ala',
    aa1: 'A',
    sc: {
      type: 'hydrophobic'
    },
    pKaC: 2.33,
    pKaN: 9.71
  }, {
    name: 'Arginine',
    aa3: 'Arg',
    aa1: 'R',
    sc: {
      type: 'positive',
      pKa: 12.1
    },
    pKaC: 2.03,
    pKaN: 9.0
  }, {
    name: 'Asparagine',
    aa3: 'Asn',
    aa1: 'N',
    sc: {
      type: 'polar'
    },
    pKaC: 2.13,
    pKaN: 9.05
  }, {
    name: 'Aspartic acid',
    aa3: 'Asp',
    aa1: 'D',
    sc: {
      type: 'negative',
      pKa: 3.71
    },
    pKaC: 1.95,
    pKaN: 9.66
  }, {
    name: 'Cysteine',
    aa3: 'Cys',
    aa1: 'C',
    sc: {
      type: 'special',
      pKa: 8.14
    },
    pKaC: 1.91,
    pKaN: 10.28
  }, {
    name: 'Glutamic acid',
    aa3: 'Glu',
    aa1: 'E',
    sc: {
      type: 'negative',
      pKa: 4.15
    },
    pKaC: 2.16,
    pKaN: 9.58
  }, {
    name: 'Glutamine',
    aa3: 'Gln',
    aa1: 'Q',
    sc: {
      type: 'polar'
    },
    pKaC: 2.18,
    pKaN: 9.0
  }, {
    name: 'Glycine',
    aa3: 'Gly',
    aa1: 'G',
    sc: {
      type: 'special'
    },
    pKaC: 2.34,
    pKaN: 9.58
  }, {
    name: 'Histidine',
    aa3: 'His',
    aa1: 'H',
    sc: {
      type: 'positive',
      pKa: 6.04
    },
    pKaC: 1.7,
    pKaN: 9.09
  }, {
    name: 'Isoleucine',
    aa3: 'Ile',
    aa1: 'I',
    sc: {
      type: 'hydrophobic'
    },
    pKaC: 2.26,
    pKaN: 9.6
  }, {
    name: 'Leucine',
    aa3: 'Leu',
    aa1: 'L',
    sc: {
      type: 'hydrophobic'
    },
    pKaC: 2.32,
    pKaN: 9.58
  }, {
    name: 'Lysine',
    aa3: 'Lys',
    aa1: 'K',
    sc: {
      type: 'positive',
      pKa: 10.67
    },
    pKaC: 2.15,
    pKaN: 9.16
  }, {
    name: 'Methionine',
    aa3: 'Met',
    aa1: 'M',
    sc: {
      type: 'hydrophobic'
    },
    pKaC: 2.16,
    pKaN: 9.08
  }, {
    name: 'Phenylalanine',
    aa3: 'Phe',
    aa1: 'F',
    sc: {
      type: 'hydrophobic'
    },
    pKaC: 2.18,
    pKaN: 9.09
  }, {
    name: 'Proline',
    aa3: 'Pro',
    aa1: 'P',
    sc: {
      type: 'special'
    },
    pKaC: 1.95,
    pKaN: 10.47
  }, {
    name: 'Serine',
    aa3: 'Ser',
    aa1: 'S',
    sc: {
      type: 'polar'
    },
    pKaC: 2.13,
    pKaN: 9.05
  }, {
    name: 'Threonine',
    aa3: 'Thr',
    aa1: 'T',
    sc: {
      type: 'polar'
    },
    pKaC: 2.2,
    pKaN: 8.96
  }, {
    name: 'Tryptophan',
    aa3: 'Trp',
    aa1: 'W',
    sc: {
      type: 'hydrophobic'
    },
    pKaC: 2.38,
    pKaN: 9.34
  }, {
    name: 'Tyrosine',
    aa3: 'Tyr',
    aa1: 'Y',
    sc: {
      type: 'hydrophobic'
    },
    pKaC: 2.24,
    pKaN: 9.04
  }, {
    name: 'Valine',
    aa3: 'Val',
    aa1: 'V',
    sc: {
      type: 'hydrophobic'
    },
    pKaC: 2.27,
    pKaN: 9.52
  }, // Additional
  {
    name: 'Selenocysteine',
    aa3: 'Sec',
    aa1: 'U'
  }, {
    name: 'Pyrrolysine',
    aa3: 'Pyl',
    aa1: 'O'
  }, // Ambiguous
  {
    name: 'Asparagine or aspartic acid',
    aa3: 'Asx',
    aa1: 'B'
  }, {
    name: 'Glutamine or glutamic acid',
    aa3: 'Glx',
    aa1: 'Z'
  }, {
    name: 'Leucine or isoleucine',
    aa3: 'Xle',
    aa1: 'J'
  }, {
    name: 'Unspecified or unknown',
    aa3: 'Xaa',
    aa1: 'X'
  }];

  function getAA(code) {
    if (code.length === 1) {
      for (let i = 0; i < aminoAcids.length; i++) {
        if (aminoAcids[i].aa1 === code) {
          return aminoAcids[i];
        }
      }
    }

    if (code.length === 3) {
      for (let i = 0; i < aminoAcids.length; i++) {
        if (aminoAcids[i].aa3 === code) {
          return aminoAcids[i];
        }
      }
    }
  }

  var getAA_1 = getAA;

  function chargePeptide(mf, options = {}) {
    if (options.pH === undefined) options.pH = 0;

    if (Array.isArray(mf)) {
      for (let i = 0; i < mf.length; i++) {
        mf[i] = chargeOnePeptide(mf[i], options);
      }

      return mf;
    } else {
      return chargeOnePeptide(mf, options);
    }
  }

  function chargeOnePeptide(mf, options) {
    let pH = options.pH; // we will allow to charge the peptide at a specific pH
    // first amino acids (N-terminal)

    if (mf.match(/^H[A-Z][a-z]{2}/)) {
      let firstAA = mf.replace(/^H([A-Z][a-z]{2}).*/, '$1');

      if (getAA_1(firstAA) && pH < getAA_1(firstAA).pKaN) {
        mf = mf.replace(/^H([^+])/, 'H+H$1');
      }
    } // last amino acids (C-terminal)


    if (mf.match(/[A-Z][a-z]{2}OH$/)) {
      let lastAA = mf.replace(/.*([A-Z][a-z]{2})OH$/, '$1');

      if (getAA_1(lastAA) && pH > getAA_1(lastAA).pKaC) {
        mf = mf.replace(/OH$/, 'O-');
      }
    } // basic AA


    if (pH < getAA_1('Arg').sc.pKa) mf = mf.replace(/(Arg)(?!\()/g, '$1(H+)');
    if (pH < getAA_1('His').sc.pKa) mf = mf.replace(/(His)(?!\()/g, '$1(H+)');
    if (pH < getAA_1('Lys').sc.pKa) mf = mf.replace(/(Lys)(?!\()/g, '$1(H+)'); // acid AA

    if (pH > getAA_1('Asp').sc.pKa) mf = mf.replace(/(Asp)(?!\()/g, '$1(H-1-)');
    if (pH > getAA_1('Glu').sc.pKa) mf = mf.replace(/(Glu)(?!\()/g, '$1(H-1-)');
    if (pH > getAA_1('Cys').sc.pKa) mf = mf.replace(/(Cys)(?!\()/g, '$1(H-1-)');
    return mf;
  }

  var chargePeptide_1$1 = chargePeptide;

  function convertAASequence(mf) {
    // this function will check if it is a sequence of aa in 1 letter or 3 letters and convert them if it is the case
    // it could be a multiline mf !
    // if it is a multiline we could make some "tricks" ...
    let newMF = mf; // SEQRES   1 B  256  MET PRO VAL GLU ILE THR VAL LYS GLU LEU LEU GLU ALA
    // SEQRES   2 B  256  GLY VAL HIS PHE GLY HIS GLU ARG LYS ARG TRP ASN PRO
    // or
    // MET PRO VAL GLU ILE THR VAL LYS GLU LEU LEU GLU ALA
    // GLY VAL HIS PHE GLY HIS GLU ARG LYS ARG TRP ASN PRO

    if (mf.search(/[A-Z]{3} [A-Z]{3} [A-Z]{3}/) > -1) {
      // this is a PDB !
      let tmpmf = mf.replace(/[\r\n]+/g, ' ');
      tmpmf = tmpmf.replace(/(SEQRES|[0-9]+| [A-Z] | [0-9A-Z]{4-50})/g, ''); // we need to correct the uppercase / lowercase

      let parts = tmpmf.split(' ');
      newMF = 'H';

      for (let i = 0; i < parts.length; i++) {
        newMF += parts[i].substr(0, 1) + parts[i].substr(1).toLowerCase();
      }

      newMF += 'OH';
    } else if (mf.includes('(') && isOneLetterCode(mf)) {
      // we expect one letter code with modification
      newMF = '';
      let nTerminal = 'H';
      let cTerminal = 'OH';
      let parenthesisCounter = 0;

      for (let i = 0; i < mf.length; i++) {
        let currentSymbol = mf[i];

        if (currentSymbol === '(' || currentSymbol === ')' || parenthesisCounter > 0) {
          if (currentSymbol === '(') {
            parenthesisCounter++;
            if (i === 0) nTerminal = '';
          }

          if (currentSymbol === ')') {
            parenthesisCounter--;
            if (i === mf.length - 1) cTerminal = '';
          }

          newMF += currentSymbol;
          continue;
        }

        newMF += convertAA1To3(currentSymbol);
      }

      newMF = nTerminal + newMF + cTerminal;
    } else if (mf.search(/[A-Z]{3}/) > -1 && mf.search(/[a-zA-Z][a-z0-9]/) === -1) {
      // UNIPROT
      //   370        380        390        400        410        420
      //GFKPNLRKTF VSGLFRESCG AHFYRGVDVK PFYIKKPVDN LFALMLILNR LRGWGVVGGM
      //
      //    430        440        450        460        470        480
      //SDPRLYKVWV RLSSQVPSMF FGGTDLAADY YVVSPPTAVS VYTKTPYGRL LADTRTSGFR
      // We remove all the number, all the spaces, etc
      newMF = `H${convertAA1To3(newMF.replace(/[^A-Z]/g, ''))}OH`;
    }

    return newMF;
  }

  function convertAA1To3(mf) {
    let newmf = '';

    for (let i = 0; i < mf.length; i++) {
      newmf += aa1To3(mf.charAt(i));
    }

    return newmf;
  }

  function aa1To3(code) {
    for (let i = 0; i < aminoAcids.length; i++) {
      if (aminoAcids[i].aa1 === code) {
        return aminoAcids[i].aa3;
      }
    }

    throw new Error(`Invalid 1 letter code: ${code}`);
  }

  var convertAASequence_1$1 = convertAASequence; // mf can contain as well parenthesis. We need to check if it is not yet a correct molecular formula

  function isOneLetterCode(mf) {
    let parenthesisLevel = 0;

    for (let char of mf) {
      if (parenthesisLevel === 0 && char.match(/[a-z]/)) return false;
      if (char === '(') parenthesisLevel++;
      if (char === ')') parenthesisLevel--;
    }

    return true;
  }

  /*
  Iotuibs:
  * minMissed (default: 0)
  * maxMissed (default: 0)
  * minResidue: 0;
  * maxResidue: infinity
  * enzyme: chymotrypsin, trypsin, glucph4, glucph8, thermolysin, cyanogenbromide : Mandatory, no default value !
   */

  function digestSequence(sequence, options = {}) {
    sequence = sequence.replace(/^H([^a-z])/, '$1').replace(/OH$/, '');
    options.enzyme = options.enzyme || 'trypsin';
    if (options.minMissed === undefined) options.minMissed = 0;
    if (options.maxMissed === undefined) options.maxMissed = 0;
    if (options.minResidue === undefined) options.minResidue = 0;
    if (options.maxResidue === undefined) options.maxResidue = Number.MAX_VALUE;
    let regexp = getRegexp(options.enzyme);
    let fragments = sequence.replace(regexp, '$1 ').split(/ /).filter(entry => entry);
    {
      let from = 0;

      for (let i = 0; i < fragments.length; i++) {
        let nbResidue = fragments[i].replace(/([A-Z][a-z][a-z])/g, ' $1').split(/ /).filter(entry => entry).length;
        fragments[i] = {
          sequence: fragments[i],
          nbResidue: nbResidue,
          from: from,
          to: from + nbResidue - 1
        };
        from += nbResidue;
      }
    }
    let results = [];

    for (let i = 0; i < fragments.length - options.minMissed; i++) {
      for (let j = options.minMissed; j <= Math.min(options.maxMissed, fragments.length - i - 1); j++) {
        let fragment = '';
        let nbResidue = 0;

        for (let k = i; k <= i + j; k++) {
          fragment += fragments[k].sequence;
          nbResidue += fragments[k].nbResidue;
        }

        let from = fragments[i].from + 1;
        let to = fragments[i + j].to + 1;

        if (fragment && nbResidue >= options.minResidue && nbResidue <= options.maxResidue) {
          results.push(`H${fragment}OH$D${from}>${to}`);
        }
      }
    }

    return results;
  }

  function getRegexp(enzyme) {
    switch (enzyme.toLowerCase().replace(/[^a-z0-9]/g, '')) {
      case 'chymotrypsin':
        return /(Phe|Tyr|Trp)(?!Pro)/g;

      case 'trypsin':
        return /(Lys|Arg)(?!Pro)/g;

      case 'lysc':
        return /(Lys)(?!Pro)/g;

      case 'glucph4':
        return /(Glu)(?!Pro|Glu)/g;

      case 'glucph8':
        return /(Asp|Glu)(?!Pro|Glu)/g;

      case 'thermolysin':
        // N-term of  Leu, Phe, Val, Ile, Ala, Met
        return /()(?=Ile|Leu|Val|Ala|Met|Phe)/g;

      case 'cyanogenbromide':
        return /(Met)/g;

      case 'any':
        return /()(?=[A-Z][a-z][a-z])/g;

      default:
        throw new Error(`Digestion enzyme: ${enzyme} is unknown`);
    }
  }

  var digestPeptide = digestSequence;

  var generatePeptideFragments = function (mf, options) {
    if (options === undefined) {
      options = {
        a: false,
        b: true,
        c: false,
        x: false,
        y: true,
        z: false,
        i: false,
        ya: false,
        yb: false,
        yc: false,
        zc: false
      };
    }

    options.maxInternal = options.maxInternal || Number.MAX_VALUE;
    options.minInternal = options.minInternal || 0;
    let mfs = []; // need to allow 0-9 to deal with neutral loss

    let mfparts = mf.replace(/([a-z)0-9])([A-Z][a-z](?=[a-z]))/g, '$1 $2').split(/ /);
    let nTerm = '';
    let cTerm = '';

    if (mfparts[0].startsWith('(')) {
      nTerm += mfparts[0];
      mfparts = mfparts.splice(1);
    }

    if (mfparts[mfparts.length - 1].includes('(')) {
      cTerm += mfparts[mfparts.length - 1].replace(/^[^()]*/, '');
      mfparts[mfparts.length - 1] = mfparts[mfparts.length - 1].replace(/\(.*/, '');
    }

    for (let i = 1; i < mfparts.length; i++) {
      nTerm += mfparts[i - 1];
      cTerm = mfparts[mfparts.length - i] + cTerm;
      addNTerm(mfs, nTerm, i, options);
      addCTerm(mfs, cTerm, i, options);
      if (options.i) mfs.push(`${mfparts[i]}HC-1O-1(+1)$i:${mfparts[i]}`);

      if (options.ya || options.yb || options.yc || options.zc) {
        // we have double fragmentations
        for (let j = i + 1; j < Math.min(mfparts.length, options.maxInternal + i + 1); j++) {
          let iTerm = '';

          if (j - i >= options.minInternal) {
            for (let k = i; k < j; k++) {
              iTerm += mfparts[k];
            }

            addITerm(mfs, iTerm, mfparts.length - i, j, options);
          }
        }
      }
    } // todo does this make sense ??? I think we should remote those 3 lines


    if (mfs.length === 0) {
      mfs = mfs.concat([mf]);
    }

    return mfs;
  };

  function addNTerm(mfs, nTerm, i, options) {
    if (options.a) mfs.push(`${nTerm}C-1O-1(+1)$a${i}`);
    if (options.b) mfs.push(`${nTerm}(+1)$b${i}`);
    if (options.c) mfs.push(`${nTerm}NH3(+1)$c${i}`);
  }

  function addITerm(mfs, iTerm, i, j, options) {
    if (options.ya) mfs.push(`H${iTerm}C-1O-1(+1)$a${j}y${i}`);
    if (options.yb) mfs.push(`H${iTerm}(+1)$b${j}y${i}`);
    if (options.yc) mfs.push(`H${iTerm}NH3(+1)$c${j}y${i}`);
    if (options.zc) mfs.push(`N-1${iTerm}NH3(+1)$c${j}z${i}`);
  }

  function addCTerm(mfs, cTerm, i, options) {
    if (options.x) mfs.push(`CO(+1)${cTerm}$x${i}`);
    if (options.y) mfs.push(`H2(+1)${cTerm}$y${i}`);
    if (options.z) mfs.push(`N-1H-1(+1)${cTerm}$z${i}`);
  }

  let aaObject = {};

  for (let i = 0; i < aminoAcids.length; i++) {
    aaObject[aminoAcids[i].aa3] = aminoAcids[i];
  }

  function calculateCharge$1(aas, pH) {
    if (!pH) pH = 7.0;
    let combined = combine(aas);
    if (!combined) return;
    let charge = calculateForPh(combined, pH);
    return Math.round(charge * 1000) / 1000;
  } // this methods required an array of aas


  function calculateIEP$1(aas) {
    let combined = combine(aas);
    if (!combined) return;
    let first = 0;
    let last = 14;
    let current = 14;
    let previous = 0;
    let currentCharge;

    while (Math.abs(current - previous) > 0.0001) {
      previous = current;
      current = (last + first) / 2;
      currentCharge = calculateForPh(combined, current);

      if (currentCharge > 0) {
        first = current;
      } else if (currentCharge < 0) {
        last = current;
      } else {
        previous = current;
      }
    }

    return Math.round(current * 1000) / 1000;
  }

  function calculateChart(aas) {
    let combined = combine(aas);
    if (!combined) return;
    let y = [];
    let x = [];
    let yAbs = [];

    for (let i = 0; i <= 14; i = i + 0.01) {
      let charge = calculateForPh(combined, i);
      x.push(i);
      y.push(charge);
      yAbs.push(Math.abs(charge));
    }

    combined.x = x;
    combined.y = y;
    combined.yAbs = yAbs;
    return combined;
  }

  function calculateForPh(combined, pH) {
    let total = 0;
    total += 1 / (1 + Math.pow(10, pH - combined.first));
    total += -1 / (1 + Math.pow(10, combined.last - pH));

    for (let key in combined.acid) {
      total += -combined.acid[key] / (1 + Math.pow(10, aaObject[key].sc.pKa - pH));
    }

    for (let key in combined.basic) {
      total += combined.basic[key] / (1 + Math.pow(10, pH - aaObject[key].sc.pKa));
    }

    return total;
  } // we will combine the amino acids


  function combine(aas) {
    let combined = {};

    if (aaObject[aas[0]]) {
      combined.first = aaObject[aas[0]].pKaN;
    } else {
      return;
    }

    if (aaObject[aas[aas.length - 1]]) {
      combined.last = aaObject[aas[aas.length - 1]].pKaC;
    } else {
      return;
    }

    combined.basic = {};
    combined.acid = {};

    for (let i = 0; i < aas.length; i++) {
      let currentAA = aas[i];
      if (!aaObject[currentAA]) return;

      if (aaObject[currentAA].sc && aaObject[currentAA].sc.type) {
        if (aaObject[currentAA].sc.type === 'positive') {
          if (!combined.basic[currentAA]) {
            combined.basic[currentAA] = 0;
          }

          combined.basic[currentAA]++;
        } else if (aaObject[currentAA].sc.type === 'negative') {
          if (!combined.acid[currentAA]) {
            combined.acid[currentAA] = 0;
          }

          combined.acid[currentAA]++;
        }
      }
    }

    return combined;
  }
  /*
   We can generate a color based on iep
   0 -> 7 means that at pH 7 it is charged negatively (blue)
   7 -> 14 means that at pH7 it is charged positively (red)
   */


  function getColor(iep) {
    if (iep < 7) {
      if (iep < 3) iep = 3;
      let white = Math.round(255 - (7 - iep) * (200 / 4));
      return `rgb(${white},${white},255)`;
    } else if (iep > 7) {
      if (iep > 11) iep = 11;
      let white = Math.round(255 - (iep - 7) * (200 / 4));
      return `rgb(255,${white},${white})`;
    }

    return 'rgb(255,255,255)';
  }

  var isoElectricPoint = {
    calculateIEP: calculateIEP$1,
    calculateCharge: calculateCharge$1,
    calculateChart: calculateChart,
    getColor: getColor
  };

  function splitSequence(sequence) {
    let aas = sequence.replace(/([A-Z])/g, ' $1').split(/ /);
    let begin = 0;

    while (aas[begin] === '' || aas[begin] === 'H') {
      begin++;
    }

    let end = aas.length - 1;

    while (aas[end] === 'O' || aas[end] === 'H') {
      end--;
    }

    aas = aas.slice(begin, end + 1);
    return aas;
  }

  var splitPeptide = splitSequence;

  var getInfo = function () {
    return aminoAcids;
  }; // sequence should be in the "right" format like HAlaGlyProOH


  var splitPeptide_1 = splitPeptide;
  var digestPeptide_1 = digestPeptide;

  var calculateIEP = function (sequence) {
    let aas = splitPeptide(sequence);
    let result = isoElectricPoint.calculateIEP(aas);
    return result;
  };

  var calculateIEPChart = function (sequence) {
    let aas = splitPeptide(sequence);
    let result = isoElectricPoint.calculateChart(aas);
    return result;
  };

  var getColorForIEP = function (iep) {
    return isoElectricPoint.getColor(iep);
  };

  var calculateCharge = function (sequence, ph) {
    let aas = splitPeptide(sequence);
    return isoElectricPoint.calculateCharge(aas, ph);
  };

  var generatePeptideFragments_1 = generatePeptideFragments;
  var chargePeptide_1 = chargePeptide_1$1;
  var allowNeutralLoss_1 = allowNeutralLoss_1$1;
  var convertAASequence_1 = convertAASequence_1$1;
  var sequenceToMF$1 = convertAASequence_1$1;
  var src$a = {
    getInfo: getInfo,
    splitPeptide: splitPeptide_1,
    digestPeptide: digestPeptide_1,
    calculateIEP: calculateIEP,
    calculateIEPChart: calculateIEPChart,
    getColorForIEP: getColorForIEP,
    calculateCharge: calculateCharge,
    generatePeptideFragments: generatePeptideFragments_1,
    chargePeptide: chargePeptide_1,
    allowNeutralLoss: allowNeutralLoss_1,
    convertAASequence: convertAASequence_1,
    sequenceToMF: sequenceToMF$1
  };

  function fragmentArray(sequence, options = {}) {
    const {
      digestion = {},
      protonation,
      fragmentation,
      protonationPH,
      allowNeutralLoss
    } = options;
    sequence = src$a.convertAASequence(sequence);
    let fragmentsArray = [sequence]; // do we also have some digest fragments ?

    if (digestion.enzyme) {
      let digests = src$a.digestPeptide(sequence, digestion);

      if (options.protonation) {
        digests = src$a.chargePeptide(digests, {
          pH: options.protonationPH
        });
      }

      fragmentsArray = fragmentsArray.concat(digests);
    } // allow neutral loss


    if (allowNeutralLoss) {
      sequence = src$a.allowNeutralLoss(sequence);
    } // apply protonation


    if (protonation) {
      sequence = src$a.chargePeptide(sequence, {
        pH: protonationPH
      });
    } // calculate fragmentation


    let fragments = src$a.generatePeptideFragments(sequence, fragmentation);
    fragmentsArray = fragmentsArray.concat(fragments);
    return fragmentsArray;
  }

  var fragmentPeptide = fragmentArray;

  const {
    groupsToSequence: groupsToSequence$1
  } = src$b;
  /**
   * Add a database starting from a peptidic sequence
   *
   * @param {string}         [sequences] Sequence as a string of 1 letter or 3 letters code. Could also be a correct molecular formula respecting uppercase, lowercase. It can be comma separated if you have many peptide sequences
   * @param {object}         [options={}]
   * @param {boolean}        [options.estimate=false] - estimate the number of MF without filters
   * @param {string}         [options.ionizations='']
   * @param {array}          [options.mfsArray=[]]
   * @param {boolean}        [options.protonation=false]
   * @param {number}         [options.protonationPH=7]
   * @param {boolean}        [options.allowNeutralLoss=false]
   * @param {number}         [options.limit=100000]
   *
   * @param {object}         [options.digestion={}] Object defining options for digestion
   * @param {number}         [options.digestion.minMissed=0] Minimal number of allowed missed cleavage
   * @param {number}         [options.digestion.maxMissed=0] Maximal number of allowed missed cleavage
   * @param {number}         [options.digestion.minResidue=0] Minimal number of residues
   * @param {number}         [options.digestion.maxResidue=+Infinity] Maximal number of residues
   * @param {string}         [options.digestion.enzyme] Mandatory field containing the name of the enzyme among: chymotrypsin, trypsin, glucph4, glucph8, thermolysin, cyanogenbromide
   *
   * @param {object}         [options.fragmentation={}] Object defining options for fragmentation
   * @param {boolean}        [options.fragmentation.a=false] If true allow fragments of type 'a'
   * @param {boolean}        [options.fragmentation.b=false] If true allow fragments of type 'b'
   * @param {boolean}        [options.fragmentation.c=false] If true allow fragments of type 'c'
   * @param {boolean}        [options.fragmentation.x=false] If true allow fragments of type 'x'
   * @param {boolean}        [options.fragmentation.y=false] If true allow fragments of type 'y'
   * @param {boolean}        [options.fragmentation.z=false] If true allow fragments of type 'z'
   * @param {boolean}        [options.fragmentation.ya=false] If true allow fragments of type 'ya'
   * @param {boolean}        [options.fragmentation.yb=false] If true allow fragments of type 'yb'
   * @param {boolean}        [options.fragmentation.yc=false] If true allow fragments of type 'yc'
   * @param {boolean}        [options.fragmentation.zc=false] If true allow fragments of type 'zc'
   * @param {number}         [options.fragmentation.minInternal=0] Minimal internal fragment length
   * @param {number}         [options.fragmentation.maxInternal=+Infinity] Maximal internal fragment length
   *
   * @param {object}         [options.filter={}] Object defining options for molecular formula filter
   * @param {number}         [options.filter.precision=1000] - The precision on the experimental mass
   * @param {number}         [options.filter.targetMass] - Target mass, allows to calculate error and filter results
   * @param {Array<number>}  [options.filter.targetMasses] - Target masses: SORTED array of numbers
   * @param {Array<number>}  [options.filter.targetIntensities] - Target intensities: SORTED array of numbers
   * @param {number}         [options.filter.minEM=0] - Minimal neutral monoisotopic mass
   * @param {number}         [options.filter.maxEM=+Infinity] - Maximal neutral monoisotopic mass
   * @param {number}         [options.filter.minMSEM=0] - Minimal observed monoisotopic mass
   * @param {number}         [options.filter.maxMSEM=+Infinity] - Maximal observed monoisotopic mass
   * @param {number}         [options.filter.minCharge=-Infinity] - Minimal charge
   * @param {number}         [options.filter.maxCharge=+Infinity] - Maximal charge
   * @param {number}         [options.filter.unsaturation={}]
   * @param {number}         [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number}         [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number}         [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number}         [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {function}       [options.filter.callback] - a function to filter the MF
   */

  var fromPeptidicSequence = function fromPeptidicSequence(sequences, options = {}) {
    const {
      digestion = {},
      mfsArray: originalMFsArray = [],
      allowNeutralLoss = false,
      protonation = false,
      protonationPH = 7,
      fragmentation = {},
      filter = {},
      ionizations = '',
      limit = 100000,
      estimate = false,
      links = {}
    } = options;
    const hasLinked = sequences.includes('#');
    const mfsArrayLinked = JSON.parse(JSON.stringify(originalMFsArray));
    const mfsArrayUnlinked = JSON.parse(JSON.stringify(originalMFsArray));
    const unlinked = [];
    mfsArrayUnlinked.push(unlinked);

    for (const sequence of sequences.split(/[,:]/)) {
      let fragmentsArray = fragmentPeptide(sequence, {
        digestion,
        protonation,
        fragmentation,
        protonationPH,
        allowNeutralLoss
      });
      mfsArrayLinked.push(fragmentsArray.filter(fragment => fragment.includes('#')));
      unlinked.push(...fragmentsArray.filter(fragment => !fragment.includes('#')));
    }

    let combined = src$e(mfsArrayUnlinked, {
      ionizations,
      filter,
      estimate,
      limit,
      links
    });

    if (hasLinked) {
      combined.push(...src$e(mfsArrayLinked, {
        ionizations,
        filter,
        estimate,
        limit,
        links
      }));
    }

    if (!estimate) {
      combined.forEach(result => {
        result.sequence = groupsToSequence$1(result.parts.filter(part => part).join(' '));
      });
    }

    return combined;
  };

  /**
   * Ensure that the sequence is in uppercase taking into account possible modifications
   * @param {string} [options.circular=false]
   */

  function ensureUppercaseSequence(sequence) {
    let parenthesisCounter = 0;
    let parts = [];
    let part = '';

    for (let i = 0; i < sequence.length; i++) {
      let currentSymbol = sequence[i];

      if (currentSymbol === '(' && parenthesisCounter === 0 && part) {
        parts.push(part);
        part = currentSymbol;
      } else if (currentSymbol === ')' && parenthesisCounter === 0) {
        part += currentSymbol;
        parts.push(part);
        part = '';
      } else {
        part += currentSymbol;
      }
    }

    if (part) parts.push(part);

    for (let i = 0; i < parts.length; i++) {
      if (!parts[i].startsWith('(') && parts[i].match(/^[a-z]+$/)) {
        parts[i] = parts[i].toUpperCase();
      }
    }

    return parts.join('');
  }

  var ensureUppercaseSequence_1 = ensureUppercaseSequence;

  const {
    groups: groups$1
  } = src$b;
  /**
   * Convert a nucleic sequence to a MF
   * @param {String} sequence
   * @param {object} [options={}]
   * @param {string} [options.kind] - rna, ds-dna or dna. Default if contains U: rna, otherwise ds-dna
   * @param {string} [options.fivePrime=monophosphate] - alcohol, monophosphate, diphosphate, triphosphate
   * @param {string} [options.circular=false]
   */

  function sequenceToMF(sequence, options = {}) {
    let fivePrimeTerminal = 'HO';
    let threePrimeTerminal = 'H';
    sequence = sequence.replace(/^HO/, '');
    sequence = sequence.replace(/H$/, '');
    sequence = sequence.trim();
    if (sequence === '') return '';
    sequence = ensureUppercaseSequence_1(sequence); // if the sequence is in lowercase but the parenthesis we should convert it to uppercase

    if (sequence.match(/^[a-z]+$/)) {
      sequence = sequence.toUpperCase();
    }

    let {
      kind,
      circular,
      fivePrime = 'monophosphate'
    } = options;
    fivePrime = fivePrime.replace(/[^a-zA-Z]/g, '').toLowerCase();

    if (!kind) {
      if (sequence.includes('U')) {
        kind = 'rna';
      } else {
        kind = 'ds-dna';
      }
    }

    kind = kind.replace(/[^A-Za-z]/g, '').toLowerCase();

    if (sequence.includes('(') && kind === 'dsdna') {
      throw new Error('Nucleotide sequenceToMF: modifications not allowed for ds-DNA');
    }

    let results = [[]];
    if (kind === 'dsdna') results.push([]);
    let parenthesisCounter = 0;

    for (let i = 0; i < sequence.length; i++) {
      let currentSymbol = sequence[i];

      while (sequence[i + 1] && sequence[i + 1].match(/[a-z]/)) {
        i++;
        currentSymbol += sequence[i];
      }

      if (currentSymbol.length > 1) {
        results[0].push(currentSymbol);
        continue;
      }

      if (currentSymbol === '(' || currentSymbol === ')' || parenthesisCounter > 0) {
        if (currentSymbol === '(') {
          parenthesisCounter++;
          if (i === 0) fivePrimeTerminal = '';
        }

        if (currentSymbol === ')') {
          parenthesisCounter--;
          if (i === sequence.length - 1) threePrimeTerminal = '';
        }

        switch (kind) {
          case 'dna':
          case 'rna':
            results[0].push(currentSymbol);
            break;

          default:
            // eslint-disable-next-line no-console
            console.warn(`Nucleotide sequenceToMF with modification: unknown kind: ${kind}`);
        }

        continue;
      }

      let nucleotideType = i === 0 ? fivePrime : 'monophosphate';
      currentSymbol = currentSymbol.replace(/[ \t\r\n]/, '');
      if (!currentSymbol) continue;

      switch (kind) {
        case 'dna':
          results[0].push(desoxyNucleotides[nucleotideType][currentSymbol]);
          break;

        case 'rna':
          results[0].push(oxyNucleotides[nucleotideType][currentSymbol]);
          break;

        case 'dsdna':
          results[0].push(desoxyNucleotides[nucleotideType][currentSymbol]);
          results[1].unshift(desoxyNucleotides[nucleotideType][complementary[currentSymbol]]);
          break;

        default:
          // eslint-disable-next-line no-console
          console.warn(`Nucleotide sequenceToMF: unknown kind: ${kind}`);
      }
    }

    if (!circular) {
      results.forEach(result => result.unshift(fivePrimeTerminal));
      results.forEach(result => result.push(threePrimeTerminal));
    }

    return results.map(result => result.join('')).join('.');
  }

  var sequenceToMF_1 = sequenceToMF;
  const complementary = {
    A: 'T',
    T: 'A',
    C: 'G',
    G: 'C'
  };
  const desoxyNucleotides = {
    alcohol: {},
    monophosphate: {},
    diphosphate: {},
    triphosphate: {}
  };
  groups$1.filter(group => group.kind === 'DNA').forEach(group => {
    if (group.oneLetter) {
      desoxyNucleotides.alcohol[group.oneLetter] = group.symbol;
    }
  });
  groups$1.filter(group => group.kind === 'DNAp').forEach(group => {
    if (group.oneLetter) {
      desoxyNucleotides.monophosphate[group.oneLetter] = group.symbol;
    }
  });
  groups$1.filter(group => group.kind === 'NucleotideP').forEach(group => {
    if (group.oneLetter) {
      desoxyNucleotides.monophosphate[group.oneLetter] = group.symbol;
    }
  });
  groups$1.filter(group => group.kind === 'DNApp').forEach(group => {
    if (group.oneLetter) {
      desoxyNucleotides.diphosphate[group.oneLetter] = group.symbol;
    }
  });
  groups$1.filter(group => group.kind === 'DNAppp').forEach(group => {
    if (group.oneLetter) {
      desoxyNucleotides.triphosphate[group.oneLetter] = group.symbol;
    }
  });
  const oxyNucleotides = {
    alcohol: {},
    monophosphate: {},
    diphosphate: {},
    triphosphate: {}
  };
  groups$1.filter(group => group.kind === 'RNA').forEach(group => {
    if (group.oneLetter) {
      oxyNucleotides.alcohol[group.oneLetter] = group.symbol;
    }
  });
  groups$1.filter(group => group.kind === 'RNAp').forEach(group => {
    if (group.oneLetter) {
      oxyNucleotides.monophosphate[group.oneLetter] = group.symbol;
    }
  });
  groups$1.filter(group => group.kind === 'NucleotideP').forEach(group => {
    if (group.oneLetter) {
      oxyNucleotides.monophosphate[group.oneLetter] = group.symbol;
    }
  });
  groups$1.filter(group => group.kind === 'RNApp').forEach(group => {
    if (group.oneLetter) {
      oxyNucleotides.diphosphate[group.oneLetter] = group.symbol;
    }
  });
  groups$1.filter(group => group.kind === 'RNAppp').forEach(group => {
    if (group.oneLetter) {
      oxyNucleotides.triphosphate[group.oneLetter] = group.symbol;
    }
  });

  function furanThreeTerm(nucleotide) {
    // last residue should become a furan
    let parts = nucleotide.replace(/ /g, '').replace(/([a-z)0-9])([A-Z][a-z](?=[a-z]))/g, '$1 $2').split(/ /);
    let last = parts.pop();

    if (!last.match(/D[atcg]mp(.*)$/)) {
      // eslint-disable-next-line no-console
      console.warn(`furanThreeTerm can not remove a non monophosphate nucleic acid: ${last}`);
      return parts.join('') + last;
    }

    return parts.join('') + last.replace(/D[atcg]mp(.*)$/, 'Furp');
  }

  var furanThreeTerm_1 = furanThreeTerm;

  function addFiveTerm(mfs, fiveTerm, i, options) {
    if (options.a) mfs.push(`${fiveTerm}O-1H-1$a${i}`); // neutral ok

    if (options.ab && i > 1) mfs.push(`${furanThreeTerm_1(fiveTerm)}$a${i}-B`); // A minus base

    if (options.b) mfs.push(`${fiveTerm}H$b${i}`); // need to add an hydrogen, see: https://books.google.ch/books?id=B57e37bJjqAC&pg=PA172&lpg=PA172&dq=oligonucleotide+b+fragmentation&source=bl&ots=mRr29Pexx2&sig=1NUQcWV-wuj6o9q81my86AVoRto&hl=fr&sa=X&ved=2ahUKEwjI5M3yn-7fAhUJMewKHQR6Bcs4ChDoATADegQIBhAB#v=onepage&q&f=true

    if (options.c) mfs.push(`${fiveTerm}PO2$c${i}`); // neutral ok

    if (options.d) mfs.push(`${fiveTerm}PO3H2$d${i}`);
    if (options.dh2o) mfs.push(`${fiveTerm}PO2$d${i}-H2O`);
  }

  var addFiveTerm_1 = addFiveTerm;

  const MF$1 = src$h.MF;

  function mfDiff(mfString1, mfString2) {
    let mf1 = new MF$1(mfString1).getInfo().atoms;
    let mf2 = new MF$1(mfString2).getInfo().atoms;
    let atoms = Object.keys(mf1);
    Object.keys(mf2).forEach(atom => {
      if (!atoms.includes(atom)) atoms.push(atom);
    });
    let mf = '';

    for (let atom of atoms) {
      let diff = (mf1[atom] || 0) - (mf2[atom] || 0);
      if (diff) mf += atom + diff;
    }

    return new MF$1(mf).toMF();
  }

  var mfDiff_1 = mfDiff;

  const mfLosses = {};
  ['Amp', 'Tmp', 'Cmp', 'Gmp', 'Ump'].forEach(nucleotide => {
    mfLosses[nucleotide] = {
      code: nucleotide.charAt(0),
      diff: mfDiff_1('Rmp', nucleotide)
    };
  });
  ['Damp', 'Dtmp', 'Dcmp', 'Dgmp', 'Dump'].forEach(nucleotide => {
    mfLosses[nucleotide] = {
      code: nucleotide.charAt(1).toUpperCase(),
      diff: mfDiff_1('Drmp', nucleotide)
    };
  });

  function baseLoss(nucleotide) {
    // any residue can loose a base
    let results = [];

    for (let key in mfLosses) {
      const base = mfLosses[key];

      if (nucleotide.includes(key)) {
        results.push(`${nucleotide}(${base.diff})$${base.code}*`);
      }
    }

    return results;
  }

  var baseLoss_1 = baseLoss;

  function addFiveTermBaseLoss(mfs, fiveTerm, i, options) {
    if (!options.abcdBaseLoss) return;
    let loss = baseLoss_1(fiveTerm);
    loss.forEach(mf => {
      if (options.a) {
        mfs.push(`${mf}`.replace('$', `O-1H-1$a${i} `));
      }

      if (options.b) {
        mfs.push(`${mf}`.replace('$', `H-1$b${i} `));
      }

      if (options.c) {
        mfs.push(`${mf}`.replace('$', `PO2$c${i} `));
      }

      if (options.d) {
        mfs.push(`${mf}`.replace('$', `PO3H2$d${i} `));
      }
    });
  }

  var addFiveTermBaseLoss_1 = addFiveTermBaseLoss;

  function addInternalTerm(mfs, internal, ter3, ter5, options = {}) {
    if (options.aw) {
      // without base loss
      mfs.push(`HO${internal}O-1H-1$w${ter3}:a${ter5}`); // A W
    }

    if (options.bw) {
      // without base loss
      mfs.push(`HO${internal}H$w${ter3}:b${ter5}`); // B W
    }

    if (options.abw) {
      // with base loss
      let fragment = furanThreeTerm_1(internal);
      mfs.push(`HO${fragment}$w${ter3}:a${ter5}-B`); // A minus base - W
    }

    if (options.aby) {
      // with base loss
      let fragment = furanThreeTerm_1(internal);
      mfs.push(`O-2P-1${fragment}$y${ter3}:a${ter5}-B`); // A minus base - Y
    }
  }

  var addInternalTerm_1 = addInternalTerm;

  function addThreeTerm(mfs, threeTerm, i, options) {
    if (options.w) mfs.push(`HO${threeTerm}$w${i}`); // neutral ok

    if (options.x) mfs.push(`H-1${threeTerm}$x${i}`); // neutral ok

    if (options.y) mfs.push(`O-2P-1${threeTerm}$y${i}`); // neutral ok

    if (options.z) mfs.push(`O-3H-2P-1${threeTerm}$z${i}`); // neutral ok

    if (options.zch2) mfs.push(`O-3H-4C-1P-1${threeTerm}$z${i}-CH2`); // TODO to confirm
  }

  var addThreeTerm_1 = addThreeTerm;

  function addThreeTermBaseLoss(mfs, threeTerm, i, options) {
    if (!options.wxyzBaseLoss) return;
    let loss = baseLoss_1(threeTerm);
    loss.forEach(mf => {
      if (options.w) {
        mfs.push(`HO${mf}`.replace('$', `$w${i} `));
      }

      if (options.x) {
        mfs.push(`H-1${mf}`.replace('$', `$x${i} `));
      }

      if (options.y) {
        mfs.push(`O-2P-1${mf}`.replace('$', `$y${i} `));
      }

      if (options.z) {
        mfs.push(`O-3H-1P-1(+)${mf}`.replace('$', `$z${i} `));
      }
    });
  }

  var addThreeTermBaseLoss_1 = addThreeTermBaseLoss;

  var generateFragments = function generateFragments(mf, options) {
    if (options === undefined) {
      options = {
        a: false,
        ab: false,
        b: false,
        c: false,
        d: false,
        dh2o: false,
        w: false,
        x: false,
        y: false,
        z: false,
        zch2: false,
        aw: false,
        bw: false,
        abw: false,
        aby: false,
        abcdBaseLoss: false,
        wxyzBaseLoss: false
      };
    }

    let mfs = []; // need to allow 0-9 to deal with neutral loss

    let mfparts = mf.replace(/([a-z)0-9])([A-Z][a-z](?=[a-z]))/g, '$1 $2').split(/ /);
    let fiveTerm = '';
    let threeTerm = '';

    if (mfparts[0].startsWith('(')) {
      fiveTerm += mfparts[0];
      mfparts = mfparts.splice(1);
    }

    if (mfparts[mfparts.length - 1].includes('(')) {
      threeTerm += mfparts[mfparts.length - 1].replace(/^[^()]*/, '');
      mfparts[mfparts.length - 1] = mfparts[mfparts.length - 1].replace(/\(.*/, '');
    }

    for (let ter5 = 1; ter5 < mfparts.length; ter5++) {
      fiveTerm += mfparts[ter5 - 1];
      threeTerm = mfparts[mfparts.length - ter5] + threeTerm;
      addFiveTerm_1(mfs, fiveTerm, ter5, options);
      addFiveTermBaseLoss_1(mfs, fiveTerm, ter5, options);
      addThreeTerm_1(mfs, threeTerm, ter5, options);
      addThreeTermBaseLoss_1(mfs, threeTerm, ter5, options);
    }

    for (let i = 1; i < mfparts.length - 1; i++) {
      let internal = '';

      for (let j = i; j < mfparts.length - 1; j++) {
        internal += mfparts[j];

        if (j > i) {
          addInternalTerm_1(mfs, internal, mfparts.length - i, j + 1, options);
        }
      }
    }

    return mfs;
  };

  var src$9 = {
    sequenceToMF: sequenceToMF_1,
    generateFragments: generateFragments,
    furanThreeTerm: furanThreeTerm_1,
    baseLoss: baseLoss_1
  };

  const {
    groupsToSequence
  } = src$b;
  /**
   * Add a database starting from a peptidic sequence
   *
   * @param {string} [sequence] Sequence as a string of 1 letter or 3 letters code. Could also be a correct molecular formula respecting uppercase, lowercase
   * @param {object} [options={}]
   * @param {boolean}       [options.estimate=false] - estimate the number of MF without filters
   * @param {number}         [options.limit=100000]
   * @param {string} [options.ionizations='']
   * @param {object} [options.info={}]
   * @param {string} [options.info.kind] - rna, ds-dna or dna. Default if contains U: rna, otherwise ds-dna
   * @param {string} [options.info.fivePrime=monophosphate] - alcohol, monophosphate, diphosphate, triphosphate
   * @param {string} [options.info.circular=false]
   * @param {array}   [options.mfsArray=[]]
   * @param {object}  [options.fragmentation={}] Object defining options for fragmentation
   * @param {boolean} [options.fragmentation.a=false] If true allow fragments of type 'a'
   * @param {boolean} [options.fragmentation.ab=false] If true allow fragments of type 'a' minus base
   * @param {boolean} [options.fragmentation.b=false] If true allow fragments of type 'b'
   * @param {boolean} [options.fragmentation.c=false] If true allow fragments of type 'c'
   * @param {boolean} [options.fragmentation.d=false] If true allow fragments of type 'd'
   * @param {boolean} [options.fragmentation.dh2o=false] If true allow fragments of type 'd' with water loss
   * @param {boolean} [options.fragmentation.w=false] If true allow fragments of type 'w'
   * @param {boolean} [options.fragmentation.x=false] If true allow fragments of type 'x'
   * @param {boolean} [options.fragmentation.y=false] If true allow fragments of type 'y'
   * @param {boolean} [options.fragmentation.z=false] If true allow fragments of type 'z'
   * @param {boolean} [options.baseLoss=false] If true allow base loss at all the positions
   *
   * @param {object} [options.filter={}] Object defining options for molecular formula filter
   * @param {number} [options.filter.minMass=0] - Minimal monoisotopic mass
   * @param {number} [options.filter.maxMass=+Infinity] - Maximal monoisotopic mass
   * @param {number} [options.filter.minEM=0] - Minimal neutral monoisotopic mass
   * @param {number} [options.filter.maxEM=+Infinity] - Maximal neutral monoisotopic mass
   * @param {number} [options.filter.minMSEM=0] - Minimal observed monoisotopic mass
   * @param {number} [options.filter.maxMSEM=+Infinity] - Maximal observed monoisotopic mass
   * @param {number} [options.filter.minCharge=-Infinity] - Minimal charge
   * @param {number} [options.filter.maxCharge=+Infinity] - Maximal charge
   * @param {number} [options.filter.unsaturation={}]
   * @param {number} [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number} [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number} [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number} [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   */

  var fromNucleicSequence = function fromNucleicSequence(sequencesString, options = {}) {
    const {
      mfsArray = [],
      fragmentation = {},
      filter = {},
      ionizations = '',
      info = {},
      estimate = false,
      limit = 100000
    } = options;
    let sequences = src$9.sequenceToMF(sequencesString, info).split('.');
    let fragmentsArray = sequences.slice(); // calculate fragmentation

    for (let i = 0; i < sequences.length; i++) {
      let sequence = sequences[i];
      let fragments = src$9.generateFragments(sequence, fragmentation);

      if (i === 1) {
        // complementary sequence
        fragments = fragments.map(fragment => fragment.replace(/\$/g, '$cmp-'));
      }

      fragmentsArray = fragmentsArray.concat(fragments);

      if (fragmentation.baseLoss) {
        fragmentsArray = fragmentsArray.concat(src$9.baseLoss(sequence));
      }
    }

    mfsArray.push(fragmentsArray);
    let combined = src$e(mfsArray, {
      ionizations,
      filter,
      uniqueMFs: false,
      estimate,
      limit
    });

    if (Array.isArray(combined)) {
      // not an estimation
      combined.forEach(result => {
        result.sequence = groupsToSequence(result.parts.filter(part => part).join(' '));
      });
    }

    return combined;
  };

  const toString$2 = Object.prototype.toString;
  function isAnyArray(object) {
    return toString$2.call(object).endsWith('Array]');
  }

  var src$8 = /*#__PURE__*/Object.freeze({
    __proto__: null,
    'default': isAnyArray
  });

  var isArray$1 = /*@__PURE__*/getAugmentedNamespace(src$8);

  function _interopDefaultLegacy$2(e) {
    return e && typeof e === 'object' && 'default' in e ? e : {
      'default': e
    };
  }

  var isArray__default$1 = /*#__PURE__*/_interopDefaultLegacy$2(isArray$1);

  function max$4(input, options = {}) {
    if (!isArray__default$1['default'](input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }

    const {
      fromIndex = 0,
      toIndex = input.length
    } = options;

    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');
    }

    let maxValue = input[fromIndex];

    for (let i = fromIndex + 1; i < toIndex; i++) {
      if (input[i] > maxValue) maxValue = input[i];
    }

    return maxValue;
  }

  var lib$2 = max$4;

  function _interopDefaultLegacy$1(e) {
    return e && typeof e === 'object' && 'default' in e ? e : {
      'default': e
    };
  }

  var isArray__default = /*#__PURE__*/_interopDefaultLegacy$1(isArray$1);

  function min$5(input, options = {}) {
    if (!isArray__default['default'](input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }

    const {
      fromIndex = 0,
      toIndex = input.length
    } = options;

    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');
    }

    let minValue = input[fromIndex];

    for (let i = fromIndex + 1; i < toIndex; i++) {
      if (input[i] < minValue) minValue = input[i];
    }

    return minValue;
  }

  var lib$1 = min$5;

  function maybeToPrecision(value, digits) {
    if (value < 0) {
      value = 0 - value;

      if (typeof digits === 'number') {
        return `- ${value.toPrecision(digits)}`;
      } else {
        return `- ${value.toString()}`;
      }
    } else {
      if (typeof digits === 'number') {
        return value.toPrecision(digits);
      } else {
        return value.toString();
      }
    }
  }

  function checkArraySize(x, y) {
    if (!isAnyArray(x) || !isAnyArray(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$1 {
    constructor() {
      if (new.target === BaseRegression$1) {
        throw new Error('BaseRegression must be subclassed');
      }
    }

    predict(x) {
      if (typeof x === 'number') {
        return this._predict(x);
      } else if (isAnyArray(x)) {
        const y = [];

        for (let i = 0; i < x.length; i++) {
          y.push(this._predict(x[i]));
        }

        return y;
      } else {
        throw new TypeError('x must be a number or array');
      }
    }

    _predict() {
      throw new Error('_predict must be implemented');
    }

    train() {// Do nothing for this package
    }

    toString() {
      return '';
    }

    toLaTeX() {
      return '';
    }
    /**
     * Return the correlation coefficient of determination (r) and chi-square.
     * @param {Array<number>} x
     * @param {Array<number>} y
     * @return {object}
     */


    score(x, y) {
      if (!isAnyArray(x) || !isAnyArray(y) || x.length !== y.length) {
        throw new Error('x and y must be arrays of the same length');
      }

      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: r,
        r2: r * r,
        chi2: chi2,
        rmsd: Math.sqrt(rmsd / n)
      };
    }

  }

  var src$7 = /*#__PURE__*/Object.freeze({
    __proto__: null,
    'default': BaseRegression$1,
    maybeToPrecision: maybeToPrecision,
    checkArrayLength: checkArraySize
  });

  var medianQuickselect_min = createCommonjsModule$1(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); !0;) {
          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; !0;) {
            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;
    })();
  });

  function median$1(input) {
    if (!isAnyArray(input)) {
      throw new TypeError('input must be an array');
    }

    if (input.length === 0) {
      throw new TypeError('input must not be empty');
    }

    return medianQuickselect_min(input.slice());
  }

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

  var BaseRegression = /*@__PURE__*/getAugmentedNamespace(src$7);

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

  function _interopDefault$1(ex) {
    return ex && typeof ex === 'object' && 'default' in ex ? ex['default'] : ex;
  }

  var BaseRegression__default = _interopDefault$1(BaseRegression);

  var median = _interopDefault$1(require$$0$1);

  class TheilSenRegression extends BaseRegression__default {
    /**
     * Theil–Sen estimator
     * https://en.wikipedia.org/wiki/Theil%E2%80%93Sen_estimator
     * @param {Array<number>|boolean} x
     * @param {Array<number>|object} y
     * @constructor
     */
    constructor(x, y) {
      super();

      if (x === true) {
        // loads the model
        this.slope = y.slope;
        this.intercept = y.intercept;
        this.coefficients = y.coefficients;
      } else {
        // creates the model
        BaseRegression.checkArrayLength(x, y);
        theilSen(this, x, y);
      }
    }

    toJSON() {
      return {
        name: 'TheilSenRegression',
        slope: this.slope,
        intercept: this.intercept
      };
    }

    _predict(input) {
      return this.slope * input + this.intercept;
    }

    computeX(input) {
      return (input - this.intercept) / this.slope;
    }

    toString(precision) {
      var result = 'f(x) = ';

      if (this.slope) {
        var xFactor = BaseRegression.maybeToPrecision(this.slope, precision);
        result += `${Math.abs(xFactor - 1) < 1e-5 ? '' : `${xFactor} * `}x`;

        if (this.intercept) {
          var absIntercept = Math.abs(this.intercept);
          var operator = absIntercept === this.intercept ? '+' : '-';
          result += ` ${operator} ${BaseRegression.maybeToPrecision(absIntercept, precision)}`;
        }
      } else {
        result += BaseRegression.maybeToPrecision(this.intercept, precision);
      }

      return result;
    }

    toLaTeX(precision) {
      return this.toString(precision);
    }

    static load(json) {
      if (json.name !== 'TheilSenRegression') {
        throw new TypeError('not a Theil-Sen model');
      }

      return new TheilSenRegression(true, json);
    }

  }

  function theilSen(regression, x, y) {
    let len = x.length;
    let slopes = new Array(len * len);
    let count = 0;

    for (let i = 0; i < len; ++i) {
      for (let j = i + 1; j < len; ++j) {
        if (x[i] !== x[j]) {
          slopes[count++] = (y[j] - y[i]) / (x[j] - x[i]);
        }
      }
    }

    slopes.length = count;
    let medianSlope = median(slopes);
    let cuts = new Array(len);

    for (let i = 0; i < len; ++i) {
      cuts[i] = y[i] - medianSlope * x[i];
    }

    regression.slope = medianSlope;
    regression.intercept = median(cuts);
    regression.coefficients = [regression.intercept, regression.slope];
  }

  var lib = TheilSenRegression;

  function massShifts(similarities, options = {}) {
    const {
      minSimilarity = 0.95,
      minLength = 10
    } = options;
    let results = [];

    if (!Array.isArray(similarities)) {
      for (let key of results) {
        for (let entry of results[key]) {
          results.push(entry);
        }
      }
    } else {
      results = similarities;
    }

    results = results.filter(result => result.ms && result.ms.similarity && result.ms.similarity.value > minSimilarity);

    if (results.length < minLength) {
      throw new Error(`X rescale can not be applied. We need at least ${minLength} peaks with over ${Math.round(minSimilarity * 100)}% similarity`);
    }

    const data = results.map(result => {
      return {
        em: result.ms.em,
        delta: result.ms.delta
      };
    }).sort((a, b) => a.em - b.em);
    let shifts = {
      x: [],
      y: []
    };
    data.forEach(datum => {
      shifts.x.push(Number(datum.em));
      shifts.y.push(Number(datum.delta));
    });
    const regression = new lib(shifts.x, shifts.y);
    let minX = lib$1(shifts.x);
    let maxX = lib$2(shifts.x);
    let shiftsPPM = {
      x: shifts.x,
      y: []
    };
    data.forEach(datum => {
      shiftsPPM.y.push(Number(datum.delta / datum.em * 1e6));
    });
    let regressionChart = {
      x: [],
      y: []
    };

    for (let i = minX; i < maxX; i += (maxX - minX) / 1000) {
      regressionChart.x.push(i);
      regressionChart.y.push(regression.predict(i));
    }

    return {
      shifts,
      shiftsPPM,
      fit: regressionChart,
      score: regression.score(shifts.x, shifts.y),
      // eslint-disable-next-line no-new-func
      predictFct: regression.predict.bind(regression),
      tex: regression.toLaTeX(3),
      slope: regression.slope,
      intercept: regression.intercept,
      predictFctString: `${regression.slope} * mass + ${regression.intercept}`
    };
  }

  var massShifts_1 = massShifts;

  const matcher = src$f.general;
  /**
      Searching by various criteria. This mass will not take into account the mass
      of the mass of the electron
  * @param {object}   [filter={}}]
  * @param {number}   [filter.minMW=0] - Minimal molecular weight
  * @param {number}   [filter.maxMW=+Infinity] - Maximal molecular weight
  * @param {number}   [filter.minEM=0] - Minimal monoisotopic mass
  * @param {number}   [filter.maxEM=+Infinity] - Maximal monoisotopic mass
  * @param {number}   [filter.minCharge=-Infinity] - Minimal charge
  * @param {number}   [filter.maxCharge=+Infinity] - Maximal charge
  * @param {object}   [filter.unsaturation={}}]
  * @param {number}   [filter.unsaturation.min=-Infinity] - Minimal unsaturation
  * @param {number}   [filter.unsaturation.max=+Infinity] - Maximal unsaturation
  * @param {number}   [filter.unsaturation.onlyInteger=false] - Integer unsaturation
  * @param {number}   [filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
  * @param {object}   [filter.atoms] - object of atom:{min, max}

  * @param {object}   [options={}]
  * @param {array}    [options.databases] - an array containing the name of the databases so search, by default all
  * @param {boolean}  [options.flatten=false] - should we return the array as a flat result

   *
  */

  var search = function search(filter, options = {}) {
    let {
      databases = Object.keys(this.databases),
      flatten = false
    } = options;
    let results = {};

    for (let database of databases) {
      results[database] = this.databases[database].filter(entry => matcher(entry, filter));
    }

    if (flatten) {
      let flattenResults = [];

      for (let database of databases) {
        for (let entry of results[database]) {
          entry.database = database;
          flattenResults.push(entry);
        }
      }

      return flattenResults;
    } else {
      return results;
    }
  };

  /**
  Search for an experimental monoisotopic mass
  * @param {number}   msem - The observed monoisotopic mass
  * @param {object}   [options={}]
  * @param {array}    [options.databases] - an array containing the name of the databases so search, by default all
  * @param {boolean}  [options.flatten=false] - should we return the array as a flat result
  * @param {object}   [options.filter={}]
  * @param {string}   [options.ionizations] - list the allowed ionizations possibilities
   * @param {number}         [options.filter.targetMass] - Target mass, allows to calculate error and filter results
   * @param {Array<number>}  [options.filter.targetMasses] - Target masses: SORTED array of numbers
   * @param {Array<number>}  [options.filter.targetIntensities] - Target intensities: SORTED array of numbers
   * @param {number}         [options.filter.minEM=0] - Minimal monoisotopic mass
   * @param {number}         [options.filter.maxEM=+Infinity] - Maximal monoisotopic mass
   * @param {number}         [options.filter.minMSEM=0] - Minimal monoisotopic mass observed by mass
   * @param {number}         [options.filter.maxMSEM=+Infinity] - Maximal monoisotopic mass observed by mass
   * @param {number}         [options.filter.minCharge=-Infinity] - Minimal charge
   * @param {number}         [options.filter.maxCharge=+Infinity] - Maximal charge
   * @param {object}         [options.filter.unsaturation={}}]
   * @param {number}         [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
   * @param {number}         [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
   * @param {number}         [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
   * @param {number}         [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
   * @param {object}         [options.filter.callback] - a function to filter the MF
   * @param {object}         [options.filter.atoms] - object of atom:{min, max}
  */


  var searchMSEM = function searchMSEM(msem, options = {}) {
    let filter = Object.assign({}, options.filter || {}, {
      targetMass: msem
    });
    let {
      databases = Object.keys(this.databases),
      flatten = false
    } = options;
    let ionizations = preprocessIonizations(options.ionizations);
    let results = {};

    for (let database of databases) {
      results[database] = [];
    }

    for (let ionization of ionizations) {
      filter.ionization = ionization;

      for (let database of databases) {
        for (let entry of this.databases[database]) {
          let match = msemMatcher(entry, filter);

          if (match) {
            results[database].push(Object.assign({}, entry, {
              ms: match.ms,
              ionization: match.ionization
            }));
          }
        }
      }
    }

    if (flatten) {
      let flattenResults = [];

      for (let database of databases) {
        for (let entry of results[database]) {
          entry.database = database;
          flattenResults.push(entry);
        }
      }

      flattenResults.sort((a, b) => Math.abs(a.ms.ppm) - Math.abs(b.ms.ppm));
      return flattenResults;
    } else {
      Object.keys(results).forEach(k => results[k].sort((a, b) => Math.abs(a.ms.ppm) - Math.abs(b.ms.ppm)));
      return results;
    }
  };

  var fetchJSON = async function fetchJSONBrowser(url) {
    const result = await browser(url);
    return result.json();
  };

  const {
    ELECTRON_MASS: ELECTRON_MASS$1
  } = constants;
  /**
   * Generates a database 'pubchem' based on all molecular formula available
   * in the database and a monoisotopic mass.
   * @param {number} mass - Observed monoisotopic mass
   * @param {object} [options={}]
   * @param {string} [options.databaseName='pubchem']
   * @param {string} [options.ionizations=''] - string containing a comma separated list of modifications
   * @param {number} [options.precision=1000] - Precision of the monoisotopic mass in ppm
   * @param {number} [options.limit=1000] - Maximal number of entries to return
   * @param {number} [options.minPubchemEntries=5] - Minimal number of molecules having a specific MF
   * @param {number} [options.allowNeutralMolecules=false] - Should we display uncharged molecules (non observable by mass)
   * @param {number} [options.url='https://pubchem.cheminfo.org/mfs/em'] - URL of the webservice
   */

  var searchPubchem = async function searchPubchem(mass, options = {}) {
    const {
      url = 'https://pubchem.cheminfo.org/mfs/em',
      precision = 1000,
      limit = 1000,
      minPubchemEntries = 5,
      allowNeutralMolecules = false
    } = options;
    let promises = [];
    let ionizations = preprocessIonizations(options.ionizations);

    for (let ionization of ionizations) {
      let realMass = mass * ionization.charge - ionization.em + ELECTRON_MASS$1 * ionization.charge;
      promises.push(fetchJSON(`${url}?em=${realMass}&precision=${precision}&limit=${limit}&minPubchemEntries=${minPubchemEntries}`));
    }

    let results = await Promise.all(promises);
    let mfs = [];

    for (let i = 0; i < results.length; i++) {
      for (let mf of results[i].result) {
        try {
          let mfInfo = new src$h.MF(mf.mf).getInfo();
          mfInfo.ionization = ionizations[i];
          mfInfo.em = mfInfo.monoisotopicMass;
          mfInfo.ms = getMsInfo(mfInfo, {
            targetMass: mass,
            allowNeutralMolecules
          }).ms;
          mfInfo.info = {
            nbPubchemEntries: mf.total
          };
          mfs.push(mfInfo);
        } catch (e) {
          // eslint-disable-next-line no-console
          console.warn(`${e}`);
        }
      }
    } // because we can combine many ionizations we should resort the data


    mfs.sort((a, b) => Math.abs(a.ms.ppm) - Math.abs(b.ms.ppm));
    return mfs;
  };

  const GAUSSIAN_EXP_FACTOR = -4 * Math.LN2;
  const ROOT_PI_OVER_LN2 = Math.sqrt(Math.PI / Math.LN2);
  const ROOT_THREE = Math.sqrt(3);
  const ROOT_2LN2 = Math.sqrt(2 * Math.LN2);
  const ROOT_2LN2_MINUS_ONE = Math.sqrt(2 * Math.LN2) - 1;

  // https://en.wikipedia.org/wiki/Error_function#Inverse_functions
  // This code yields to a good approximation
  // If needed a better implementation using polynomial can be found on https://en.wikipedia.org/wiki/Error_function#Inverse_functions
  function erfinv(x) {
    let a = 0.147;
    if (x === 0) return 0;
    let ln1MinusXSqrd = Math.log(1 - x * x);
    let lnEtcBy2Plus2 = ln1MinusXSqrd / 2 + 2 / (Math.PI * a);
    let firstSqrt = Math.sqrt(lnEtcBy2Plus2 ** 2 - ln1MinusXSqrd / a);
    let secondSqrt = Math.sqrt(firstSqrt - lnEtcBy2Plus2);
    return secondSqrt * (x > 0 ? 1 : -1);
  }

  class Gaussian {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=4*LN2/(PI*FWHM)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.sd] - Standard deviation, if it's defined options.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      this.fwhm = options.sd ? Gaussian.widthToFWHM(2 * options.sd) : options.fwhm ? options.fwhm : 500;
      this.height = options.height === undefined ? Math.sqrt(-GAUSSIAN_EXP_FACTOR / Math.PI) / this.fwhm : options.height;
    }
    /**
     * Calculate a gaussian shape
     * @param {object} [options = {}]
     * @param {number} [options.factor = 6] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {number} [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return {Float64Array} y values
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.min(Math.ceil(this.fwhm * factor), Math.pow(2, 25) - 1);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      const data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a gaussian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @returns {number} - the y value of gaussian with the current parameters.
     */


    fct(x) {
      return Gaussian.fct(x, this.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999]
     * @returns {number}
     */


    getFactor(area = 0.9999) {
      return Gaussian.getFactor(area);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return Gaussian.getArea(this.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
     * //https://mathworld.wolfram.com/GaussianFunction.html
     * @param {number} width - Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      //https://mathworld.wolfram.com/GaussianFunction.html
      return Gaussian.widthToFWHM(width);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/GaussianFunction.html
     * @param {number} fwhm - Full Width at Half Maximum.
     * @returns {number} width
     */


    fwhmToWidth(fwhm = this.fwhm) {
      return Gaussian.fwhmToWidth(fwhm);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  Gaussian.fct = function fct(x, fwhm = 500) {
    return Math.exp(GAUSSIAN_EXP_FACTOR * Math.pow(x / fwhm, 2));
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
   * //https://mathworld.wolfram.com/GaussianFunction.html
   * @param {number} width - Width between the inflection points
   * @returns {number} fwhm
   */


  Gaussian.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_2LN2;
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/GaussianFunction.html
   * @param {number} fwhm - Full Width at Half Maximum.
   * @returns {number} width
   */


  Gaussian.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_2LN2;
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {object} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Gaussian.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1
    } = options;
    return height * ROOT_PI_OVER_LN2 * fwhm / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage.
   * @param {number} [area=0.9999]
   * @returns {number}
   */


  Gaussian.getFactor = function getFactor(area = 0.9999) {
    return Math.sqrt(2) * erfinv(area);
  };

  class Lorentzian {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=2/(PI*FWHM)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.sd] - Standard deviation, if it's defined options.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      this.fwhm = options.fwhm === undefined ? 500 : options.fwhm;
      this.height = options.height === undefined ? 2 / Math.PI / this.fwhm : options.height;
    }
    /**
     * Calculate a lorentzian shape
     * @param {object} [options = {}]
     * @param {number} [options.factor = Math.tan(Math.PI * (0.9999 - 0.5))] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {number} [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return {Float64Array} y values
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.min(Math.ceil(this.fwhm * factor), Math.pow(2, 25) - 1);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      const data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a lorentzian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @returns {number} - the y value of lorentzian with the current parameters.
     */


    fct(x) {
      return Lorentzian.fct(x, this.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999]
     * @returns {number}
     */


    getFactor(area = 0.9999) {
      return Lorentzian.getFactor(area);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return Lorentzian.getArea(this.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of width between the inflection points of a specific shape from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/LorentzianFunction.html
     * @param {number} [fwhm] - Full Width at Half Maximum.
     * @returns {number} width between the inflection points
     */


    fwhmToWidth(fwhm = this.fwhm) {
      return Lorentzian.fwhmToWidth(fwhm);
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) of a specific shape from the width between the inflection points.
     * //https://mathworld.wolfram.com/LorentzianFunction.html
     * @param {number} [width] Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      return Lorentzian.widthToFWHM(width);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  Lorentzian.fct = function fct(x, fwhm) {
    const squareFWHM = fwhm * fwhm;
    return squareFWHM / (4 * Math.pow(x, 2) + squareFWHM);
  };
  /**
   * Compute the value of width between the inflection points of a specific shape from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/LorentzianFunction.html
   * @param {number} [fwhm] - Full Width at Half Maximum.
   * @returns {number} width between the inflection points
   */


  Lorentzian.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_THREE;
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) of a specific shape from the width between the inflection points.
   * //https://mathworld.wolfram.com/LorentzianFunction.html
   * @param {number} [width] Width between the inflection points
   * @returns {number} fwhm
   */


  Lorentzian.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_THREE;
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {*} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Lorentzian.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1
    } = options;
    return height * Math.PI * fwhm / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage
   * @param {number} [area=0.9999]
   * @returns {number}
   */


  Lorentzian.getFactor = function getFactor(area = 0.9999) {
    return 2 * Math.tan(Math.PI * (area - 0.5));
  };

  class PseudoVoigt {
    /**
     * @param {object} [options={}]
     * @param {number} [options.height=1/(mu*FWHM/sqrt(4*LN2/PI)+(1-mu)*fwhm*PI*0.5)] Define the height of the peak, by default area=1 (normalized)
     * @param {number} [options.fwhm=500] - Full Width at Half Maximum in the number of points in FWHM.
     * @param {number} [options.mu=0.5] - ratio of gaussian contribution.
     */
    constructor(options = {}) {
      this.mu = options.mu === undefined ? 0.5 : options.mu;
      this.fwhm = options.fwhm === undefined ? 500 : options.fwhm;
      this.height = options.height === undefined ? 1 / (this.mu / Math.sqrt(-GAUSSIAN_EXP_FACTOR / Math.PI) * this.fwhm + (1 - this.mu) * this.fwhm * Math.PI / 2) : options.height;
    }
    /**
     * Calculate a linear combination of gaussian and lorentzian function width an same full width at half maximum
     * @param { object } [options = {}]
     * @param { number } [options.factor = 2 * Math.tan(Math.PI * (0.9999 - 0.5))] - Number of time to take fwhm in the calculation of the length.Default covers 99.99 % of area.
     * @param { number } [options.length = fwhm * factor + 1] - total number of points to calculate
     * @return { object } - { fwhm, data<Float64Array>} - An with the number of points at half maximum and the array of y values covering the 99.99 % of the area.
     */


    getData(options = {}) {
      let {
        length,
        factor = this.getFactor()
      } = options;

      if (!length) {
        length = Math.ceil(this.fwhm * factor);
        if (length % 2 === 0) length++;
      }

      const center = (length - 1) / 2;
      let data = new Float64Array(length);

      for (let i = 0; i <= center; i++) {
        data[i] = this.fct(i - center) * this.height;
        data[length - 1 - i] = data[i];
      }

      return data;
    }
    /**
     * Return a parameterized function of a linear combination of Gaussian and Lorentzian shapes where the full width at half maximum are the same for both kind of shapes (see README for equation).
     * @param {number} [x] x value to calculate.
     * @returns {number} - the y value of a pseudo voigt with the current parameters.
     */


    fct(x) {
      return PseudoVoigt.fct(x, this.fwhm, this.mu);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific area coverage
     * @param {number} [area=0.9999] - required area to be coverage
     * @param {number} [mu=this.mu] - ratio of gaussian contribution.
     * @returns {number}
     */


    getFactor(area = 0.9999, mu = this.mu) {
      return PseudoVoigt.getFactor(area, mu);
    }
    /**
     * Calculate the area of the shape.
     * @returns {number} - returns the area.
     */


    getArea() {
      return PseudoVoigt.getArea(this.fwhm, {
        height: this.height,
        mu: this.mu
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FMHM) from width between the inflection points.
     * @param {number} width - width between the inflection points
     * @param {number} [mu = 0.5] - ratio of gaussian contribution.
     * @returns {number} Full Width at Half Maximum (FMHM).
     */


    widthToFWHM(width, mu) {
      return PseudoVoigt.widthToFWHM(width, mu);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * @param {number} fwhm - Full Width at Half Maximum.
     * @param {number} [mu] - ratio of gaussian contribution.
     * @returns {number} width between the inflection points.
     */


    fwhmToWidth(fwhm = this.fwhm, mu = this.mu) {
      return PseudoVoigt.fwhmToWidth(fwhm, mu);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     */


    setFWHM(fwhm) {
      this.fwhm = fwhm;
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }
    /**
     * set a new mu
     * @param {number} mu - ratio of gaussian contribution.
     */


    setMu(mu) {
      this.mu = mu;
    }

  }
  /**
   * Return a parameterized function of a gaussian shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} fwhm - full width half maximum
   * @param {number} [mu=0.5] - ratio of gaussian contribution.
   * @returns {number} - the y value of gaussian with the current parameters.
   */

  PseudoVoigt.fct = function fct(x, fwhm, mu = 0.5) {
    return (1 - mu) * Lorentzian.fct(x, fwhm) + mu * Gaussian.fct(x, fwhm);
  };
  /**
   * Compute the value of Full Width at Half Maximum (FMHM) from width between the inflection points.
   * @param {number} width - width between the inflection points
   * @param {number} [mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} Full Width at Half Maximum (FMHM).
   */


  PseudoVoigt.widthToFWHM = function widthToFWHM(width, mu = 0.5) {
    return width * (mu * ROOT_2LN2_MINUS_ONE + 1);
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * @param {number} fwhm - Full Width at Half Maximum.
   * @param {number} [mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} width between the inflection points.
   */


  PseudoVoigt.fwhmToWidth = function fwhmToWidth(fwhm, mu = 0.5) {
    return fwhm / (mu * ROOT_2LN2_MINUS_ONE + 1);
  };
  /**
   * Calculate the area of a specific shape.
   * @param {number} fwhm - Full width at half maximum.
   * @param {*} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum y value of the shape.
   * @param {number} [options.mu = 0.5] - ratio of gaussian contribution.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  PseudoVoigt.getArea = function getArea(fwhm, options = {}) {
    let {
      height = 1,
      mu = 0.5
    } = options;
    return fwhm * height * (mu * ROOT_PI_OVER_LN2 + (1 - mu) * Math.PI) / 2;
  };
  /**
   * Calculate the number of times FWHM allows to reach a specific area coverage
   * @param {number} [area=0.9999] - required area to be coverage
   * @param {number} [mu=this.mu] - ratio of gaussian contribution.
   * @returns {number}
   */


  PseudoVoigt.getFactor = function getFactor(area = 0.9999, mu = 0.5) {
    return mu < 1 ? Lorentzian.getFactor(area) : Gaussian.getFactor(area);
  };

  let axis = ['x', 'y'];
  class Gaussian2D {
    /**
     * @param {object} [options = {}]
     * @param {number} [options.height=4*LN2/(PI*xFWHM*yFWHM)] Define the height of the peak, by default area=1 (normalized).
     * @param {number} [options.fwhm = 500] - Full Width at Half Maximum in the number of points in FWHM used if x or y has not the fwhm property.
     * @param {object} [options.x] - Options for x axis.
     * @param {number} [options.x.fwhm = fwhm] - Full Width at Half Maximum in the number of points in FWHM for x axis.
     * @param {number} [options.x.sd] - Standard deviation for x axis, if it's defined options.x.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     * @param {object} [options.y] - Options for y axis.
     * @param {number} [options.y.fwhm = fwhm] - Full Width at Half Maximum in the number of points in FWHM for y axis.
     * @param {number} [options.y.sd] - Standard deviation for y axis, if it's defined options.y.fwhm will be ignored and the value will be computed sd * Math.sqrt(8 * Math.LN2);
     */
    constructor(options = {}) {
      let {
        fwhm: globalFWHM = 500
      } = options;

      for (let i of axis) {
        let fwhm;

        if (!options[i]) {
          fwhm = globalFWHM;
        } else {
          fwhm = options[i].sd ? Gaussian2D.widthToFWHM(2 * options[i].sd) : options[i].fwhm || globalFWHM;
        }

        this[i] = {
          fwhm
        };
      }

      this.height = options.height === undefined ? -GAUSSIAN_EXP_FACTOR / Math.PI / this.x.fwhm / this.y.fwhm : options.height;
    }
    /**
     * Calculate a Gaussian2D shape
     * @param {object} [options = {}]
     * @param {number} [options.factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {object} [options.x] - parameter for x axis.
     * @param {number} [options.x.length=fwhm*factor+1] - length on x axis.
     * @param {number} [options.x.factor=factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @param {object} [options.y] - parameter for y axis.
     * @param {number} [options.y.length=fwhm*factor+1] - length on y axis.
     * @param {number} [options.y.factor=factor] - Number of time to take fwhm to calculate length. Default covers 99.99 % of area.
     * @return {Array<Float64Array>} - z values.
     */


    getData(options = {}) {
      let {
        x = {},
        y = {},
        factor = this.getFactor(),
        length
      } = options;
      let xLength = x.length || length;

      if (!xLength) {
        let {
          factor: xFactor = factor
        } = x;
        xLength = Math.min(Math.ceil(this.x.fwhm * xFactor), Math.pow(2, 25) - 1);
        if (xLength % 2 === 0) xLength++;
      }

      let yLength = y.length || length;

      if (!yLength) {
        let {
          factor: yFactor = factor
        } = y;
        yLength = Math.min(Math.ceil(this.y.fwhm * yFactor), Math.pow(2, 25) - 1);
        if (yLength % 2 === 0) yLength++;
      }

      const xCenter = (xLength - 1) / 2;
      const yCenter = (yLength - 1) / 2;
      const data = new Array(xLength);

      for (let i = 0; i < xLength; i++) {
        data[i] = new Array(yLength);
      }

      for (let i = 0; i < xLength; i++) {
        for (let j = 0; j < yLength; j++) {
          data[i][j] = this.fct(i - xCenter, j - yCenter) * this.height;
        }
      }

      return data;
    }
    /**
     * Return the intensity value of a 2D gaussian shape (see README for equation).
     * @param {number} x - x value to calculate.
     * @param {number} y - y value to calculate.
     * @returns {number} - the z value of bi-dimensional gaussian with the current parameters.
     */


    fct(x, y) {
      return Gaussian2D.fct(x, y, this.x.fwhm, this.y.fwhm);
    }
    /**
     * Calculate the number of times FWHM allows to reach a specific volume coverage.
     * @param {number} [volume=0.9999]
     * @returns {number}
     */


    getFactor(volume = 0.9999) {
      return Gaussian2D.getFactor(volume);
    }
    /**
     * Calculate the volume of the shape.
     * @returns {number} - returns the volume.
     */


    getVolume() {
      return Gaussian2D.getVolume(this.x.fwhm, this.y.fwhm, {
        height: this.height
      });
    }
    /**
     * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
     * //https://mathworld.wolfram.com/Gaussian2DFunction.html
     * @param {number} width - Width between the inflection points
     * @returns {number} fwhm
     */


    widthToFWHM(width) {
      //https://mathworld.wolfram.com/Gaussian2DFunction.html
      return Gaussian2D.widthToFWHM(width);
    }
    /**
     * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
     * //https://mathworld.wolfram.com/Gaussian2DFunction.html
     * @param {number} fwhm - Full Width at Half Maximum.
     * @returns {number} width
     */


    fwhmToWidth(fwhm = this.x.fwhm) {
      return Gaussian2D.fwhmToWidth(fwhm);
    }
    /**
     * set a new full width at half maximum
     * @param {number} fwhm - full width at half maximum
     * @param {string|Array<string>} axisLabel - label of axis, if it is undefined fwhm is set to both axis.
     */


    setFWHM(fwhm, axisLabel) {
      if (!axisLabel) axisLabel = axis;
      if (!Array.isArray(axisLabel)) axisLabel = [axisLabel];

      for (let i of axisLabel) {
        let axisName = i.toLowerCase();

        if (axisName !== 'y' && axisName !== 'x') {
          throw new Error('axis label should be x or y');
        }

        this[axisName].fwhm = fwhm;
      }
    }
    /**
     * set a new height
     * @param {number} height - The maximal intensity of the shape.
     */


    setHeight(height) {
      this.height = height;
    }

  }
  /**
   * Return a parameterized function of a Gaussian2D shape (see README for equation).
   * @param {number} x - x value to calculate.
   * @param {number} y - y value to calculate.
   * @param {number} fwhmX - full width half maximum in the x axis.
   * @param {number} fwhmY - full width half maximum in the y axis.
   * @returns {number} - the z value of bi-dimensional gaussian with the current parameters.
   */

  Gaussian2D.fct = function fct(x, y, xFWHM = 500, yFWHM = 500) {
    return Math.exp(GAUSSIAN_EXP_FACTOR * (Math.pow(x / xFWHM, 2) + Math.pow(y / yFWHM, 2)));
  };
  /**
   * Compute the value of Full Width at Half Maximum (FWHM) from the width between the inflection points.
   * //https://mathworld.wolfram.com/Gaussian2DFunction.html
   * @param {number} width - Width between the inflection points
   * @returns {number} fwhm
   */


  Gaussian2D.widthToFWHM = function widthToFWHM(width) {
    return width * ROOT_2LN2;
  };
  /**
   * Compute the value of width between the inflection points from Full Width at Half Maximum (FWHM).
   * //https://mathworld.wolfram.com/Gaussian2DFunction.html
   * @param {number} fwhm - Full Width at Half Maximum.
   * @returns {number} width
   */


  Gaussian2D.fwhmToWidth = function fwhmToWidth(fwhm) {
    return fwhm / ROOT_2LN2;
  };
  /**
   * Calculate the volume of a specific shape.
   * @param {number} xFWHM - Full width at half maximum for x axis.
   * @param {number} yFWHM - Full width at half maximum for y axis.
   * @param {object} [options = {}] - options.
   * @param {number} [options.height = 1] - Maximum z value of the shape.
   * @returns {number} - returns the area of the specific shape and parameters.
   */


  Gaussian2D.getVolume = function getVolume(xFWHM, yFWHM, options = {}) {
    let {
      height = 1
    } = options;
    return height * Math.PI * xFWHM * yFWHM / Math.LN2 / 4;
  };
  /**@TODO look for a better factor
   * Calculate the number of times FWHM allows to reach a specific volume coverage.
   * @param {number} [volume=0.9999]
   * @returns {number}
   */


  Gaussian2D.getFactor = function getFactor(volume = 0.9999) {
    return Math.sqrt(2) * erfinv(volume);
  };

  function getShapeGenerator(options) {
    let {
      kind = 'Gaussian',
      options: shapeOptions
    } = options;

    switch (kind.toLowerCase().replace(/[^a-z^0-9]/g, '')) {
      case 'gaussian':
        return new Gaussian(shapeOptions);

      case 'lorentzian':
        return new Lorentzian(shapeOptions);

      case 'pseudovoigt':
        return new PseudoVoigt(shapeOptions);

      case 'gaussian2d':
        return new Gaussian2D(shapeOptions);

      default:
        throw new Error(`Unknown kind: ${kind}`);
    }
  }

  function addBaseline(data, baselineFct) {
    if (!baselineFct) return data;
    let xs = data.x;
    let ys = data.y;

    for (let i = 0; i < xs.length; i++) {
      ys[i] += baselineFct(xs[i]);
    }

    return data;
  }

  var defaultSource$1 = Math.random;

  var randomUniform = (function sourceRandomUniform(source) {
    function randomUniform(min, max) {
      min = min == null ? 0 : +min;
      max = max == null ? 1 : +max;
      if (arguments.length === 1) max = min, min = 0;else max -= min;
      return function () {
        return source() * max + min;
      };
    }

    randomUniform.source = sourceRandomUniform;
    return randomUniform;
  })(defaultSource$1);

  var randomNormal = (function sourceRandomNormal(source) {
    function randomNormal(mu, sigma) {
      var x, r;
      mu = mu == null ? 0 : +mu;
      sigma = sigma == null ? 1 : +sigma;
      return function () {
        var y; // If available, use the second previously-generated uniform random.

        if (x != null) y = x, x = null; // Otherwise, generate a new x and y.
        else do {
            x = source() * 2 - 1;
            y = source() * 2 - 1;
            r = x * x + y * y;
          } while (!r || r > 1);
        return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r);
      };
    }

    randomNormal.source = sourceRandomNormal;
    return randomNormal;
  })(defaultSource$1);

  const LOOP = 8;
  const FLOAT_MUL = 1 / 16777216;
  const sh1 = 15;
  const sh2 = 18;
  const sh3 = 11;

  function multiply_uint32(n, m) {
    n >>>= 0;
    m >>>= 0;
    const nlo = n & 0xffff;
    const nhi = n - nlo;
    return (nhi * m >>> 0) + nlo * m >>> 0;
  }

  class XSadd {
    constructor(seed = Date.now()) {
      this.state = new Uint32Array(4);
      this.init(seed);
      this.random = this.getFloat.bind(this);
    }
    /**
     * Returns a 32-bit integer r (0 <= r < 2^32)
     */


    getUint32() {
      this.nextState();
      return this.state[3] + this.state[2] >>> 0;
    }
    /**
     * Returns a floating point number r (0.0 <= r < 1.0)
     */


    getFloat() {
      return (this.getUint32() >>> 8) * FLOAT_MUL;
    }

    init(seed) {
      if (!Number.isInteger(seed)) {
        throw new TypeError('seed must be an integer');
      }

      this.state[0] = seed;
      this.state[1] = 0;
      this.state[2] = 0;
      this.state[3] = 0;

      for (let i = 1; i < LOOP; i++) {
        this.state[i & 3] ^= i + multiply_uint32(1812433253, this.state[i - 1 & 3] ^ this.state[i - 1 & 3] >>> 30 >>> 0) >>> 0;
      }

      this.periodCertification();

      for (let i = 0; i < LOOP; i++) {
        this.nextState();
      }
    }

    periodCertification() {
      if (this.state[0] === 0 && this.state[1] === 0 && this.state[2] === 0 && this.state[3] === 0) {
        this.state[0] = 88; // X

        this.state[1] = 83; // S

        this.state[2] = 65; // A

        this.state[3] = 68; // D
      }
    }

    nextState() {
      let t = this.state[0];
      t ^= t << sh1;
      t ^= t >>> sh2;
      t ^= this.state[3] << sh3;
      this.state[0] = this.state[1];
      this.state[1] = this.state[2];
      this.state[2] = this.state[3];
      this.state[3] = t;
    }

  }

  function addNoise(data, percent = 0, options = {}) {
    const {
      distribution = 'uniform',
      seed
    } = options;
    let generateRandomNumber;

    switch (distribution) {
      case 'uniform':
        {
          generateRandomNumber = getRandom(randomUniform, seed, -0.5, 0.5);
          break;
        }

      case 'normal':
        {
          generateRandomNumber = getRandom(randomNormal, seed);
          break;
        }

      default:
        throw new Error(`Unknown distribution ${options.distribution}`);
    }

    if (!percent) return data;
    let ys = data.y;
    let factor = percent * findMax(ys) / 100;

    for (let i = 0; i < ys.length; i++) {
      ys[i] += generateRandomNumber() * factor;
    }

    return data;
  }

  function getRandom(func, seed, ...args) {
    return typeof seed === 'number' ? func.source(new XSadd(seed).random)(...args) : func(...args);
  }

  function findMax(array) {
    let max = Number.MIN_VALUE;

    for (let item of array) {
      if (item > max) max = item;
    }

    return max;
  }

  class SpectrumGenerator$1 {
    /**
     *
     * @param {object} [options={}]
     * @param {number} [options.from=0]
     * @param {number} [options.to=0]
     * @param {function} [options.nbPoints=10001]
     * @param {number} [options.factor] default value depends of the shape in order to cover 99.99% of the surface
     * @param {object} [options.shape={kind:'gaussian'}]
     * @param {string} [options.shape.kind] kind of shape, gaussian, lorentzian or pseudovoigt
     * @param {object} [options.shape.options] options for the shape (like `mu` for pseudovoigt)
     */
    constructor(options = {}) {
      options = Object.assign({}, {
        from: 0,
        to: 1000,
        nbPoints: 10001,
        peakWidthFct: () => 5,
        shape: {
          kind: 'gaussian'
        }
      }, options);
      this.from = options.from;
      this.to = options.to;
      this.nbPoints = options.nbPoints;
      this.interval = (this.to - this.from) / (this.nbPoints - 1);
      this.peakWidthFct = options.peakWidthFct;
      this.maxPeakHeight = Number.MIN_SAFE_INTEGER;
      let shapeGenerator = getShapeGenerator(options.shape);
      this.shape = shapeGenerator;
      assertNumber(this.from, 'from');
      assertNumber(this.to, 'to');
      assertInteger(this.nbPoints, 'nbPoints');

      if (this.to <= this.from) {
        throw new RangeError('to option must be larger than from');
      }

      if (typeof this.peakWidthFct !== 'function') {
        throw new TypeError('peakWidthFct option must be a function');
      }

      this.reset();
    }

    addPeaks(peaks, options) {
      if (!Array.isArray(peaks) && (typeof peaks !== 'object' || peaks.x === undefined || peaks.y === undefined || !Array.isArray(peaks.x) || !Array.isArray(peaks.y) || peaks.x.length !== peaks.y.length)) {
        throw new TypeError('peaks must be an array or an object containing x[] and y[]');
      }

      if (Array.isArray(peaks)) {
        for (const peak of peaks) {
          this.addPeak(peak, options);
        }
      } else {
        for (let i = 0; i < peaks.x.length; i++) {
          this.addPeak([peaks.x[i], peaks.y[i]], options);
        }
      }

      return this;
    }
    /**
     *
     * @param {[x,y]|[x,y,w]|{x,y,width}} [peak]
     * @param {*} options
     */


    addPeak(peak, options = {}) {
      if (typeof peak !== 'object' || peak.length !== 2 && peak.length !== 3 && (peak.x === undefined || peak.y === undefined)) {
        throw new Error('peak must be an array with two (or three) values or an object with {x,y,width?}');
      }

      let xPosition;
      let intensity;
      let peakWidth;
      let peakOptions;

      if (Array.isArray(peak)) {
        [xPosition, intensity, peakWidth, peakOptions] = peak;
      } else {
        xPosition = peak.x;
        intensity = peak.y;
        peakWidth = peak.width;
        peakOptions = peak.options;
      }

      if (intensity > this.maxPeakHeight) this.maxPeakHeight = intensity;
      let {
        width = peakWidth === undefined ? this.peakWidthFct(xPosition) : peakWidth,
        widthLeft,
        widthRight,
        shape: shapeOptions
      } = options;

      if (peakOptions) {
        Object.assign(shapeOptions || {}, peakOptions || {});
      }

      let shapeGenerator = shapeOptions ? getShapeGenerator(shapeOptions) : this.shape;
      if (!widthLeft) widthLeft = width;
      if (!widthRight) widthRight = width;
      let factor = options.factor === undefined ? shapeGenerator.getFactor() : options.factor;
      const firstValue = xPosition - widthLeft / 2 * factor;
      const lastValue = xPosition + widthRight / 2 * factor;
      const firstPoint = Math.max(0, Math.floor((firstValue - this.from) / this.interval));
      const lastPoint = Math.min(this.nbPoints - 1, Math.ceil((lastValue - this.from) / this.interval));
      const middlePoint = Math.round((xPosition - this.from) / this.interval); // PEAK SHAPE MAY BE ASYMMETRC (widthLeft and widthRight) !
      // we calculate the left part of the shape

      shapeGenerator.setFWHM(widthLeft);

      for (let index = firstPoint; index < Math.max(middlePoint, 0); index++) {
        this.data.y[index] += intensity * shapeGenerator.fct(this.data.x[index] - xPosition);
      } // we calculate the right part of the gaussian


      shapeGenerator.setFWHM(widthRight);

      for (let index = Math.min(middlePoint, lastPoint); index <= lastPoint; index++) {
        this.data.y[index] += intensity * shapeGenerator.fct(this.data.x[index] - xPosition);
      }

      return this;
    }

    addBaseline(baselineFct) {
      addBaseline(this.data, baselineFct);
      return this;
    }

    addNoise(percent, options) {
      addNoise(this.data, percent, options);
      return this;
    }

    getSpectrum(options = {}) {
      if (typeof options === 'boolean') {
        options = {
          copy: options
        };
      }

      const {
        copy = true,
        threshold = 0
      } = options;

      if (threshold) {
        let minPeakHeight = this.maxPeakHeight * threshold;
        let x = [];
        let y = [];

        for (let i = 0; i < this.data.x.length; i++) {
          if (this.data.y[i] >= minPeakHeight) {
            x.push(this.data.x[i]);
            y.push(this.data.y[i]);
          }
        }

        return {
          x,
          y
        };
      }

      if (copy) {
        return {
          x: this.data.x.slice(),
          y: this.data.y.slice()
        };
      } else {
        return this.data;
      }
    }

    reset() {
      const spectrum = this.data = {
        x: new Float64Array(this.nbPoints),
        y: new Float64Array(this.nbPoints)
      };

      for (let i = 0; i < this.nbPoints; i++) {
        spectrum.x[i] = this.from + i * this.interval;
      }

      return this;
    }

  }

  function assertInteger(value, name) {
    if (!Number.isInteger(value)) {
      throw new TypeError(`${name} option must be an integer`);
    }
  }

  function assertNumber(value, name) {
    if (!Number.isFinite(value)) {
      throw new TypeError(`${name} option must be a number`);
    }
  }

  function generateSpectrum(peaks, options = {}) {
    const generator = new SpectrumGenerator$1(options);
    generator.addPeaks(peaks, options);
    if (options.baseline) generator.addBaseline(options.baseline);
    if (options.noise) generator.addNoise(options.noise.percent, options.noise);
    return generator.getSpectrum({
      threshold: options.threshold
    });
  }

  var src$6 = /*#__PURE__*/Object.freeze({
    __proto__: null,
    SpectrumGenerator: SpectrumGenerator$1,
    generateSpectrum: generateSpectrum
  });

  var sortX = function sortX() {
    this.ySorted = false;
    if (this.xSorted) return this;
    this.array.sort((a, b) => a.x - b.x);
    this.xSorted = true;
    return this;
  };

  var sortY = function sortY() {
    this.xSorted = false;
    if (this.ySorted) return this;
    this.array.sort((a, b) => b.y - a.y);
    this.ySorted = true;
    return this;
  };

  /**
   * Join x values if there are similar
   */

  var join = function joinX(threshold = Number.EPSILON) {
    // when we join we will use the center of mass
    let result = [];
    this.sortX();
    let current = {
      x: Number.MIN_SAFE_INTEGER,
      y: 0
    };

    for (let item of this.array) {
      if (item.x - current.x <= threshold) {
        // weighted sum
        current.x = item.y / (current.y + item.y) * (item.x - current.x) + current.x;
        current.y += item.y;
      } else {
        current = {
          x: item.x,
          y: item.y
        };
        result.push(current);
      }
    }

    this.array = result;
    this.ySorted = false;
    return this;
  };

  var topY = function topY(limit) {
    if (!limit) return this;
    if (this.array.length <= limit) return this;
    this.sortY();
    this.array.splice(limit);
    return this;
  };

  /**
   * Sum of Y to 1
   */

  var maxToOne = function maxToOne() {
    if (this.array.length === 0) return this;
    let currentMax = this.array[0].y;

    for (let item of this.array) {
      if (item.y > currentMax) currentMax = item.y;
    }

    for (let item of this.array) {
      item.y /= currentMax;
    }

    return this;
  };

  var multiply = function multiply(b, options = {}) {
    const {
      minY = 1e-8,
      maxLines = 5000,
      deltaX = 1e-2
    } = options;
    const result = new this.constructor();
    this.sortY();
    b.sortY();

    for (let entryA of this.array) {
      for (let entryB of b.array) {
        let y = entryA.y * entryB.y;
        if (y > minY) result.push(entryA.x + entryB.x, y);

        if (result.length > maxLines) {
          result.join(deltaX);
          result.topY(maxLines / 2);
        }
      }
    }

    result.join(deltaX);
    result.topY(maxLines / 2);
    this.move(result);
    return this;
  };

  var square = function square(options = {}) {
    return this.multiply(this, options);
  };

  var power = function power(p, options = {}) {
    if (p <= 0) throw new Error('power must be larger than 0');
    if (p === 1) return this;

    if (p === 2) {
      return this.square();
    }

    p--;
    let base = this.copy(); // linear time

    while (p !== 0) {
      if ((p & 1) !== 0) {
        this.multiply(base, options); // executed <= log2(p) times
      }

      p >>= 1;
      if (p !== 0) base.square(options); // executed <= log2(p) times
    }

    return this;
  };

  /**
   * Sum of Y to 1
   */

  var normalize$2 = function normalize() {
    let sum = 0;

    for (let item of this.array) {
      sum += item.y;
    }

    for (let item of this.array) {
      item.y /= sum;
    }

    return this;
  };

  var closestPointX = function closestPointX(target) {
    this.sortX();
    let low = 0;
    let high = this.array.length - 1;
    let middle = 0;

    while (high - low > 1) {
      middle = low + (high - low >> 1);

      if (this.array[middle].x < target) {
        low = middle;
      } else if (this.array[middle].x > target) {
        high = middle;
      } else {
        return this.array[middle];
      }
    }

    if (low < this.array.length - 1) {
      if (Math.abs(target - this.array[low].x) < Math.abs(this.array[low + 1].x - target)) {
        return this.array[low];
      } else {
        return this.array[low + 1];
      }
    } else {
      return this.array[low];
    }
  };

  class Distribution {
    constructor(array) {
      if (Array.isArray(array)) {
        this.array = array;
        this.xSorted = false;
        this.ySorted = false;
      } else {
        this.array = [];
        this.xSorted = true;
        this.ySorted = true;
      }
    }

    get length() {
      return this.array.length;
    }

    get xs() {
      return this.array.map(p => p.x);
    }

    get ys() {
      return this.array.map(p => p.y);
    }

    get minX() {
      if (!this.xSorted) this.sortX();
      return this.array[0].x;
    }

    get maxX() {
      if (!this.xSorted) this.sortX();
      return this.array[this.array.length - 1].x;
    }

    get minY() {
      if (!this.ySorted) this.sortY();
      return this.array[0].y;
    }

    get maxY() {
      if (!this.ySorted) this.sortY();
      return this.array[this.array.length - 1];
    }

  }

  Distribution.prototype.multiplyY = function multiplyY(value) {
    this.array.forEach(item => item.y *= value);
  };

  Distribution.prototype.setArray = function setArray(array) {
    this.array = array;
    this.xSorted = false;
    this.ySorted = false;
  };

  Distribution.prototype.move = function move(other) {
    this.xSorted = other.xSorted;
    this.ySorted = other.ySorted;
    this.array = other.array;
  };

  Distribution.prototype.copy = function copy() {
    let distCopy = new this.constructor();
    distCopy.xSorted = this.xSorted;
    distCopy.ySorted = this.ySorted;
    distCopy.array = JSON.parse(JSON.stringify(this.array));
    return distCopy;
  };

  Distribution.prototype.push = function push(x, y) {
    this.array.push({
      x,
      y
    });
    this.xSorted = false;
    this.ySorted = false;
  };
  /**
   * Appen another distribution to the current distribution
   * @param {*} distribution
   */


  Distribution.prototype.append = function append(distribution) {
    for (let item of distribution.array) {
      this.array.push(item);
    }

    this.xSorted = false;
    this.ySorted = false;
  };

  Distribution.prototype.sortX = sortX;
  Distribution.prototype.sortY = sortY;
  Distribution.prototype.join = join;
  Distribution.prototype.topY = topY;
  Distribution.prototype.maxToOne = maxToOne;
  Distribution.prototype.multiply = multiply;
  Distribution.prototype.square = square;
  Distribution.prototype.power = power;
  Distribution.prototype.normalize = normalize$2;
  Distribution.prototype.closestPointX = closestPointX;
  var Distribution_1 = Distribution;

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

  const ELECTRON_MASS = src$j.ELECTRON_MASS;
  const SpectrumGenerator = require$$1.SpectrumGenerator;
  const MF = src$h.MF;
  /**
   * An object containing two arrays
   * @typedef {object} XY
   * @property {Array<number>} x - The x array
   * @property {Array<number>} y - The y array
   */

  class IsotopicDistribution {
    /**
     * Class that manage isotopic distribution
     * @param {string|array} value - Molecular formula or an array of parts
     * @param {object} [options={}]
     * @param {string} [options.ionizations=''] - string containing a comma separated list of modifications
     * @param {number} [options.fwhm=0.01] - Amount of Dalton under which 2 peaks are joined
     * @param {number} [options.maxLines=5000] - Maximal number of lines during calculations
     * @param {number} [options.minY=1e-8] - Minimal signal height during calculations
     * @param {number} [options.ensureCase=false] - Ensure uppercase / lowercase
     * @param {number} [options.allowNeutral=true] - Should we keep the distribution if the molecule has no charge
     */
    constructor(value, options = {}) {
      if (Array.isArray(value)) {
        this.parts = JSON.parse(JSON.stringify(value));

        for (let part of this.parts) {
          part.confidence = 0;
          part.isotopesInfo = new MF(`${part.mf}(${part.ionization.mf})`).getIsotopesInfo();
        }
      } else {
        let mf = new MF(value, {
          ensureCase: options.ensureCase
        });
        let mfInfo = mf.getInfo();
        let ionizations = preprocessIonizations(options.ionizations);
        let parts = mfInfo.parts || [mfInfo];
        this.parts = [];

        for (let partOriginal of parts) {
          // we calculate information for each part
          for (const ionization of ionizations) {
            let part = JSON.parse(JSON.stringify(partOriginal));
            part.em = part.monoisotopicMass; // TODO: To remove !!! we change the name !?

            part.isotopesInfo = new MF(`${part.mf}(${ionization.mf})`).getIsotopesInfo();
            part.confidence = 0;
            let msInfo = getMsInfo(part, {
              ionization
            });
            part.ionization = msInfo.ionization;
            part.ms = msInfo.ms;
            this.parts.push(part);
          }
        }
      }

      this.cachedDistribution = undefined;
      this.fwhm = options.fwhm === undefined ? 0.01 : options.fwhm; // if fwhm is under 1e-8 there are some artifacts in the spectra

      if (this.fwhm < 1e-8) this.fwhm = 1e-8;
      this.minY = options.minY === undefined ? 1e-8 : options.minY;
      this.maxLines = options.maxLines || 5000;
      this.allowNeutral = options.allowNeutral === undefined ? true : options.allowNeutral;
    }

    getParts() {
      return this.parts;
    }
    /**
     * @return {Distribution} returns the total distribution (for all parts)
     */


    getDistribution() {
      if (this.cachedDistribution) return this.cachedDistribution;
      let options = {
        maxLines: this.maxLines,
        minY: this.minY,
        deltaX: this.fwhm
      };
      let finalDistribution = new Distribution_1();
      this.confidence = 0; // TODO need to cache each part without ionization
      // in case of many ionization we don't need to recalculate everything !

      for (let part of this.parts) {
        let totalDistribution = new Distribution_1([{
          x: 0,
          y: 1
        }]);
        let charge = part.ms.charge;
        let absoluteCharge = Math.abs(charge);

        if (charge || this.allowNeutral) {
          for (let isotope of part.isotopesInfo.isotopes) {
            if (isotope.number < 0) return [];

            if (isotope.number > 0) {
              let isotopeDistribution = new Distribution_1(isotope.distribution);
              isotopeDistribution.power(isotope.number, options);
              totalDistribution.multiply(isotopeDistribution, options);
            }
          }

          this.confidence += totalDistribution.array.reduce((sum, value) => sum + value.y, 0); // we finally deal with the charge

          if (charge) {
            totalDistribution.array.forEach(e => {
              e.x = (e.x - ELECTRON_MASS * charge) / absoluteCharge;
            });
          }

          if (totalDistribution.array) {
            totalDistribution.sortX();
            part.fromX = totalDistribution.array[0].x;
            part.toX = totalDistribution.array[totalDistribution.array.length - 1].x;
          }

          if (part.ms.target && part.ms.target.intensity && part.ms.target.intensity !== 1) {
            // intensity is the value of the monoisotopic mass !
            // need to find the intensity of the peak corresponding
            // to the monoisotopic mass
            if (part.ms.target.mass) {
              let target = totalDistribution.closestPointX(part.ms.target.mass);
              totalDistribution.multiplyY(part.ms.target.intensity / target.y);
            } else {
              totalDistribution.multiplyY(part.ms.target.intensity);
            }
          } else if (part.intensity && part.intensity !== 1) {
            totalDistribution.multiplyY(part.intensity);
          }

          part.isotopicDistribution = totalDistribution.array;

          if (finalDistribution.array.length === 0) {
            finalDistribution = totalDistribution;
          } else {
            finalDistribution.append(totalDistribution);
          }
        }
      }

      if (finalDistribution) finalDistribution.join(this.fwhm);
      this.confidence /= this.parts.length;
      this.cachedDistribution = finalDistribution;
      return finalDistribution;
    }

    getCSV() {
      return this.getText({
        delimiter: ', '
      });
    }

    getTSV() {
      return this.getText({
        delimiter: '\t'
      });
    }

    getTable(options = {}) {
      const {
        maxValue,
        xLabel = 'x',
        yLabel = 'y'
      } = options;
      let points = this.getDistribution().array;
      let factor = 1;

      if (maxValue) {
        let maxY = this.getMaxY(points);
        factor = maxValue / maxY;
      }

      return points.map(point => {
        let newPoint = {};
        newPoint[xLabel] = point.x;
        newPoint[yLabel] = point.y * factor;
        return newPoint;
      });
    }

    getText(options = {}) {
      const {
        delimiter = '\t',
        numberDecimals = 3
      } = options;
      let points = this.getDistribution().array;
      let csv = [];

      for (let point of points) {
        csv.push(`${point.x.toFixed(5)}${delimiter}${(point.y * 100).toFixed(numberDecimals)}`);
      }

      return csv.join('\n');
    }

    getMaxY(points) {
      let maxY = points[0].y;

      for (let point of points) {
        if (point.y > maxY) maxY = point.y;
      }

      return maxY;
    }
    /**
     * Returns the isotopic distirubtion
     * @return {XY} an object containing 2 properties: x:[] and y:[]
     */


    getXY(options = {}) {
      const {
        maxValue = 100
      } = options;
      let points = this.getDistribution().array;
      if (points.length === 0) return [];
      let factor = 1;

      if (maxValue) {
        let maxY = this.getMaxY(points);
        factor = maxY / maxValue;
      }

      return {
        x: points.map(a => a.x),
        y: points.map(a => a.y / factor)
      };
    }
    /**
     * Returns the isotopic distribution as the sum of gaussian
     * @param {object} [options={}]
     * @param {number} [options.gaussianWidth=10]
     * @param {number} [options.threshold=0.00001] // minimal height to return point
     * @param {number} [options.maxLength=1e6] // minimal height to return point
     * @param {number} [options.maxValue] // rescale Y to reach maxValue
     * @param {function} [options.peakWidthFct=(mz)=>(this.fwhm)]
     * @return {XY} isotopic distribution as an object containing 2 properties: x:[] and y:[]
     */


    getGaussian(options = {}) {
      const {
        peakWidthFct = () => this.fwhm,
        threshold = 0.00001,
        gaussianWidth = 10,
        maxValue,
        maxLength = 1e6
      } = options;
      let points = this.getTable({
        maxValue
      });
      if (points.length === 0) return {
        x: [],
        y: []
      };
      const from = Math.floor(options.from || points[0].x - 2);
      const to = Math.ceil(options.to || points[points.length - 1].x + 2);
      const nbPoints = Math.round((to - from) * gaussianWidth / this.fwhm + 1);

      if (nbPoints > maxLength) {
        throw Error(`Number of points is over the maxLength: ${nbPoints}>${maxLength}`);
      }

      let gaussianOptions = {
        from,
        to,
        nbPoints,
        peakWidthFct
      };
      let spectrumGenerator = new SpectrumGenerator(gaussianOptions);

      for (let point of points) {
        spectrumGenerator.addPeak([point.x, point.y]);
      }

      let spectrum = spectrumGenerator.getSpectrum({
        threshold
      });
      return spectrum;
    }

  }

  var IsotopicDistribution_1 = IsotopicDistribution;

  var src$5 = IsotopicDistribution_1;

  var array$2 = createCommonjsModule$1(function (module, exports) {

    function compareNumbers(a, b) {
      return a - b;
    }
    /**
     * Computes the sum of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.sum = function sum(values) {
      var sum = 0;

      for (var i = 0; i < values.length; i++) {
        sum += values[i];
      }

      return sum;
    };
    /**
     * Computes the maximum of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.max = function max(values) {
      var max = values[0];
      var l = values.length;

      for (var i = 1; i < l; i++) {
        if (values[i] > max) max = values[i];
      }

      return max;
    };
    /**
     * Computes the minimum of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.min = function min(values) {
      var min = values[0];
      var l = values.length;

      for (var i = 1; i < l; i++) {
        if (values[i] < min) min = values[i];
      }

      return min;
    };
    /**
     * Computes the min and max of the given values
     * @param {Array} values
     * @returns {{min: number, max: number}}
     */


    exports.minMax = function minMax(values) {
      var min = values[0];
      var max = values[0];
      var l = values.length;

      for (var i = 1; i < l; i++) {
        if (values[i] < min) min = values[i];
        if (values[i] > max) max = values[i];
      }

      return {
        min: min,
        max: max
      };
    };
    /**
     * Computes the arithmetic mean of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.arithmeticMean = function arithmeticMean(values) {
      var sum = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        sum += values[i];
      }

      return sum / l;
    };
    /**
     * {@link arithmeticMean}
     */


    exports.mean = exports.arithmeticMean;
    /**
     * Computes the geometric mean of the given values
     * @param {Array} values
     * @returns {number}
     */

    exports.geometricMean = function geometricMean(values) {
      var mul = 1;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        mul *= values[i];
      }

      return Math.pow(mul, 1 / l);
    };
    /**
     * Computes the mean of the log of the given values
     * If the return value is exponentiated, it gives the same result as the
     * geometric mean.
     * @param {Array} values
     * @returns {number}
     */


    exports.logMean = function logMean(values) {
      var lnsum = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        lnsum += Math.log(values[i]);
      }

      return lnsum / l;
    };
    /**
     * Computes the weighted grand mean for a list of means and sample sizes
     * @param {Array} means - Mean values for each set of samples
     * @param {Array} samples - Number of original values for each set of samples
     * @returns {number}
     */


    exports.grandMean = function grandMean(means, samples) {
      var sum = 0;
      var n = 0;
      var l = means.length;

      for (var i = 0; i < l; i++) {
        sum += samples[i] * means[i];
        n += samples[i];
      }

      return sum / n;
    };
    /**
     * Computes the truncated mean of the given values using a given percentage
     * @param {Array} values
     * @param {number} percent - The percentage of values to keep (range: [0,1])
     * @param {boolean} [alreadySorted=false]
     * @returns {number}
     */


    exports.truncatedMean = function truncatedMean(values, percent, alreadySorted) {
      if (alreadySorted === undefined) alreadySorted = false;

      if (!alreadySorted) {
        values = [].concat(values).sort(compareNumbers);
      }

      var l = values.length;
      var k = Math.floor(l * percent);
      var sum = 0;

      for (var i = k; i < l - k; i++) {
        sum += values[i];
      }

      return sum / (l - 2 * k);
    };
    /**
     * Computes the harmonic mean of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.harmonicMean = function harmonicMean(values) {
      var sum = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        if (values[i] === 0) {
          throw new RangeError('value at index ' + i + 'is zero');
        }

        sum += 1 / values[i];
      }

      return l / sum;
    };
    /**
     * Computes the contraharmonic mean of the given values
     * @param {Array} values
     * @returns {number}
     */


    exports.contraHarmonicMean = function contraHarmonicMean(values) {
      var r1 = 0;
      var r2 = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        r1 += values[i] * values[i];
        r2 += values[i];
      }

      if (r2 < 0) {
        throw new RangeError('sum of values is negative');
      }

      return r1 / r2;
    };
    /**
     * Computes the median of the given values
     * @param {Array} values
     * @param {boolean} [alreadySorted=false]
     * @returns {number}
     */


    exports.median = function median(values, alreadySorted) {
      if (alreadySorted === undefined) alreadySorted = false;

      if (!alreadySorted) {
        values = [].concat(values).sort(compareNumbers);
      }

      var l = values.length;
      var half = Math.floor(l / 2);

      if (l % 2 === 0) {
        return (values[half - 1] + values[half]) * 0.5;
      } else {
        return values[half];
      }
    };
    /**
     * Computes the variance of the given values
     * @param {Array} values
     * @param {boolean} [unbiased=true] - if true, divide by (n-1); if false, divide by n.
     * @returns {number}
     */


    exports.variance = function variance(values, unbiased) {
      if (unbiased === undefined) unbiased = true;
      var theMean = exports.mean(values);
      var theVariance = 0;
      var l = values.length;

      for (var i = 0; i < l; i++) {
        var x = values[i] - theMean;
        theVariance += x * x;
      }

      if (unbiased) {
        return theVariance / (l - 1);
      } else {
        return theVariance / l;
      }
    };
    /**
     * Computes the standard deviation of the given values
     * @param {Array} values
     * @param {boolean} [unbiased=true] - if true, divide by (n-1); if false, divide by n.
     * @returns {number}
     */


    exports.standardDeviation = function standardDeviation(values, unbiased) {
      return Math.sqrt(exports.variance(values, unbiased));
    };

    exports.standardError = function standardError(values) {
      return exports.standardDeviation(values) / Math.sqrt(values.length);
    };
    /**
     * IEEE Transactions on biomedical engineering, vol. 52, no. 1, january 2005, p. 76-
     * Calculate the standard deviation via the Median of the absolute deviation
     *  The formula for the standard deviation only holds for Gaussian random variables.
     * @returns {{mean: number, stdev: number}}
     */


    exports.robustMeanAndStdev = function robustMeanAndStdev(y) {
      var mean = 0,
          stdev = 0;
      var length = y.length,
          i = 0;

      for (i = 0; i < length; i++) {
        mean += y[i];
      }

      mean /= length;
      var averageDeviations = new Array(length);

      for (i = 0; i < length; i++) averageDeviations[i] = Math.abs(y[i] - mean);

      averageDeviations.sort(compareNumbers);

      if (length % 2 === 1) {
        stdev = averageDeviations[(length - 1) / 2] / 0.6745;
      } else {
        stdev = 0.5 * (averageDeviations[length / 2] + averageDeviations[length / 2 - 1]) / 0.6745;
      }

      return {
        mean: mean,
        stdev: stdev
      };
    };

    exports.quartiles = function quartiles(values, alreadySorted) {
      if (typeof alreadySorted === 'undefined') alreadySorted = false;

      if (!alreadySorted) {
        values = [].concat(values).sort(compareNumbers);
      }

      var quart = values.length / 4;
      var q1 = values[Math.ceil(quart) - 1];
      var q2 = exports.median(values, true);
      var q3 = values[Math.ceil(quart * 3) - 1];
      return {
        q1: q1,
        q2: q2,
        q3: q3
      };
    };

    exports.pooledStandardDeviation = function pooledStandardDeviation(samples, unbiased) {
      return Math.sqrt(exports.pooledVariance(samples, unbiased));
    };

    exports.pooledVariance = function pooledVariance(samples, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var sum = 0;
      var length = 0,
          l = samples.length;

      for (var i = 0; i < l; i++) {
        var values = samples[i];
        var vari = exports.variance(values);
        sum += (values.length - 1) * vari;
        if (unbiased) length += values.length - 1;else length += values.length;
      }

      return sum / length;
    };

    exports.mode = function mode(values) {
      var l = values.length,
          itemCount = new Array(l),
          i;

      for (i = 0; i < l; i++) {
        itemCount[i] = 0;
      }

      var itemArray = new Array(l);
      var count = 0;

      for (i = 0; i < l; i++) {
        var index = itemArray.indexOf(values[i]);
        if (index >= 0) itemCount[index]++;else {
          itemArray[count] = values[i];
          itemCount[count] = 1;
          count++;
        }
      }

      var maxValue = 0,
          maxIndex = 0;

      for (i = 0; i < count; i++) {
        if (itemCount[i] > maxValue) {
          maxValue = itemCount[i];
          maxIndex = i;
        }
      }

      return itemArray[maxIndex];
    };

    exports.covariance = function covariance(vector1, vector2, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var mean1 = exports.mean(vector1);
      var mean2 = exports.mean(vector2);
      if (vector1.length !== vector2.length) throw 'Vectors do not have the same dimensions';
      var cov = 0,
          l = vector1.length;

      for (var i = 0; i < l; i++) {
        var x = vector1[i] - mean1;
        var y = vector2[i] - mean2;
        cov += x * y;
      }

      if (unbiased) return cov / (l - 1);else return cov / l;
    };

    exports.skewness = function skewness(values, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var theMean = exports.mean(values);
      var s2 = 0,
          s3 = 0,
          l = values.length;

      for (var i = 0; i < l; i++) {
        var dev = values[i] - theMean;
        s2 += dev * dev;
        s3 += dev * dev * dev;
      }

      var m2 = s2 / l;
      var m3 = s3 / l;
      var g = m3 / Math.pow(m2, 3 / 2.0);

      if (unbiased) {
        var a = Math.sqrt(l * (l - 1));
        var b = l - 2;
        return a / b * g;
      } else {
        return g;
      }
    };

    exports.kurtosis = function kurtosis(values, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var theMean = exports.mean(values);
      var n = values.length,
          s2 = 0,
          s4 = 0;

      for (var i = 0; i < n; i++) {
        var dev = values[i] - theMean;
        s2 += dev * dev;
        s4 += dev * dev * dev * dev;
      }

      var m2 = s2 / n;
      var m4 = s4 / n;

      if (unbiased) {
        var v = s2 / (n - 1);
        var a = n * (n + 1) / ((n - 1) * (n - 2) * (n - 3));
        var b = s4 / (v * v);
        var c = (n - 1) * (n - 1) / ((n - 2) * (n - 3));
        return a * b - 3 * c;
      } else {
        return m4 / (m2 * m2) - 3;
      }
    };

    exports.entropy = function entropy(values, eps) {
      if (typeof eps === 'undefined') eps = 0;
      var sum = 0,
          l = values.length;

      for (var i = 0; i < l; i++) sum += values[i] * Math.log(values[i] + eps);

      return -sum;
    };

    exports.weightedMean = function weightedMean(values, weights) {
      var sum = 0,
          l = values.length;

      for (var i = 0; i < l; i++) sum += values[i] * weights[i];

      return sum;
    };

    exports.weightedStandardDeviation = function weightedStandardDeviation(values, weights) {
      return Math.sqrt(exports.weightedVariance(values, weights));
    };

    exports.weightedVariance = function weightedVariance(values, weights) {
      var theMean = exports.weightedMean(values, weights);
      var vari = 0,
          l = values.length;
      var a = 0,
          b = 0;

      for (var i = 0; i < l; i++) {
        var z = values[i] - theMean;
        var w = weights[i];
        vari += w * (z * z);
        b += w;
        a += w * w;
      }

      return vari * (b / (b * b - a));
    };

    exports.center = function center(values, inPlace) {
      if (typeof inPlace === 'undefined') inPlace = false;
      var result = values;
      if (!inPlace) result = [].concat(values);
      var theMean = exports.mean(result),
          l = result.length;

      for (var i = 0; i < l; i++) result[i] -= theMean;
    };

    exports.standardize = function standardize(values, standardDev, inPlace) {
      if (typeof standardDev === 'undefined') standardDev = exports.standardDeviation(values);
      if (typeof inPlace === 'undefined') inPlace = false;
      var l = values.length;
      var result = inPlace ? values : new Array(l);

      for (var i = 0; i < l; i++) result[i] = values[i] / standardDev;

      return result;
    };

    exports.cumulativeSum = function cumulativeSum(array) {
      var l = array.length;
      var result = new Array(l);
      result[0] = array[0];

      for (var i = 1; i < l; i++) result[i] = result[i - 1] + array[i];

      return result;
    };
  });

  var matrix$1 = createCommonjsModule$1(function (module, exports) {

    function compareNumbers(a, b) {
      return a - b;
    }

    exports.max = function max(matrix) {
      var max = -Infinity;

      for (var i = 0; i < matrix.length; i++) {
        for (var j = 0; j < matrix[i].length; j++) {
          if (matrix[i][j] > max) max = matrix[i][j];
        }
      }

      return max;
    };

    exports.min = function min(matrix) {
      var min = Infinity;

      for (var i = 0; i < matrix.length; i++) {
        for (var j = 0; j < matrix[i].length; j++) {
          if (matrix[i][j] < min) min = matrix[i][j];
        }
      }

      return min;
    };

    exports.minMax = function minMax(matrix) {
      var min = Infinity;
      var max = -Infinity;

      for (var i = 0; i < matrix.length; i++) {
        for (var j = 0; j < matrix[i].length; j++) {
          if (matrix[i][j] < min) min = matrix[i][j];
          if (matrix[i][j] > max) max = matrix[i][j];
        }
      }

      return {
        min: min,
        max: max
      };
    };

    exports.entropy = function entropy(matrix, eps) {
      if (typeof eps === 'undefined') {
        eps = 0;
      }

      var sum = 0,
          l1 = matrix.length,
          l2 = matrix[0].length;

      for (var i = 0; i < l1; i++) {
        for (var j = 0; j < l2; j++) {
          sum += matrix[i][j] * Math.log(matrix[i][j] + eps);
        }
      }

      return -sum;
    };

    exports.mean = function mean(matrix, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      var rows = matrix.length,
          cols = matrix[0].length,
          theMean,
          N,
          i,
          j;

      if (dimension === -1) {
        theMean = [0];
        N = rows * cols;

        for (i = 0; i < rows; i++) {
          for (j = 0; j < cols; j++) {
            theMean[0] += matrix[i][j];
          }
        }

        theMean[0] /= N;
      } else if (dimension === 0) {
        theMean = new Array(cols);
        N = rows;

        for (j = 0; j < cols; j++) {
          theMean[j] = 0;

          for (i = 0; i < rows; i++) {
            theMean[j] += matrix[i][j];
          }

          theMean[j] /= N;
        }
      } else if (dimension === 1) {
        theMean = new Array(rows);
        N = cols;

        for (j = 0; j < rows; j++) {
          theMean[j] = 0;

          for (i = 0; i < cols; i++) {
            theMean[j] += matrix[j][i];
          }

          theMean[j] /= N;
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return theMean;
    };

    exports.sum = function sum(matrix, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      var rows = matrix.length,
          cols = matrix[0].length,
          theSum,
          i,
          j;

      if (dimension === -1) {
        theSum = [0];

        for (i = 0; i < rows; i++) {
          for (j = 0; j < cols; j++) {
            theSum[0] += matrix[i][j];
          }
        }
      } else if (dimension === 0) {
        theSum = new Array(cols);

        for (j = 0; j < cols; j++) {
          theSum[j] = 0;

          for (i = 0; i < rows; i++) {
            theSum[j] += matrix[i][j];
          }
        }
      } else if (dimension === 1) {
        theSum = new Array(rows);

        for (j = 0; j < rows; j++) {
          theSum[j] = 0;

          for (i = 0; i < cols; i++) {
            theSum[j] += matrix[j][i];
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return theSum;
    };

    exports.product = function product(matrix, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      var rows = matrix.length,
          cols = matrix[0].length,
          theProduct,
          i,
          j;

      if (dimension === -1) {
        theProduct = [1];

        for (i = 0; i < rows; i++) {
          for (j = 0; j < cols; j++) {
            theProduct[0] *= matrix[i][j];
          }
        }
      } else if (dimension === 0) {
        theProduct = new Array(cols);

        for (j = 0; j < cols; j++) {
          theProduct[j] = 1;

          for (i = 0; i < rows; i++) {
            theProduct[j] *= matrix[i][j];
          }
        }
      } else if (dimension === 1) {
        theProduct = new Array(rows);

        for (j = 0; j < rows; j++) {
          theProduct[j] = 1;

          for (i = 0; i < cols; i++) {
            theProduct[j] *= matrix[j][i];
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return theProduct;
    };

    exports.standardDeviation = function standardDeviation(matrix, means, unbiased) {
      var vari = exports.variance(matrix, means, unbiased),
          l = vari.length;

      for (var i = 0; i < l; i++) {
        vari[i] = Math.sqrt(vari[i]);
      }

      return vari;
    };

    exports.variance = function variance(matrix, means, unbiased) {
      if (typeof unbiased === 'undefined') {
        unbiased = true;
      }

      means = means || exports.mean(matrix);
      var rows = matrix.length;
      if (rows === 0) return [];
      var cols = matrix[0].length;
      var vari = new Array(cols);

      for (var j = 0; j < cols; j++) {
        var sum1 = 0,
            sum2 = 0,
            x = 0;

        for (var i = 0; i < rows; i++) {
          x = matrix[i][j] - means[j];
          sum1 += x;
          sum2 += x * x;
        }

        if (unbiased) {
          vari[j] = (sum2 - sum1 * sum1 / rows) / (rows - 1);
        } else {
          vari[j] = (sum2 - sum1 * sum1 / rows) / rows;
        }
      }

      return vari;
    };

    exports.median = function median(matrix) {
      var rows = matrix.length,
          cols = matrix[0].length;
      var medians = new Array(cols);

      for (var i = 0; i < cols; i++) {
        var data = new Array(rows);

        for (var j = 0; j < rows; j++) {
          data[j] = matrix[j][i];
        }

        data.sort(compareNumbers);
        var N = data.length;

        if (N % 2 === 0) {
          medians[i] = (data[N / 2] + data[N / 2 - 1]) * 0.5;
        } else {
          medians[i] = data[Math.floor(N / 2)];
        }
      }

      return medians;
    };

    exports.mode = function mode(matrix) {
      var rows = matrix.length,
          cols = matrix[0].length,
          modes = new Array(cols),
          i,
          j;

      for (i = 0; i < cols; i++) {
        var itemCount = new Array(rows);

        for (var k = 0; k < rows; k++) {
          itemCount[k] = 0;
        }

        var itemArray = new Array(rows);
        var count = 0;

        for (j = 0; j < rows; j++) {
          var index = itemArray.indexOf(matrix[j][i]);

          if (index >= 0) {
            itemCount[index]++;
          } else {
            itemArray[count] = matrix[j][i];
            itemCount[count] = 1;
            count++;
          }
        }

        var maxValue = 0,
            maxIndex = 0;

        for (j = 0; j < count; j++) {
          if (itemCount[j] > maxValue) {
            maxValue = itemCount[j];
            maxIndex = j;
          }
        }

        modes[i] = itemArray[maxIndex];
      }

      return modes;
    };

    exports.skewness = function skewness(matrix, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var means = exports.mean(matrix);
      var n = matrix.length,
          l = means.length;
      var skew = new Array(l);

      for (var j = 0; j < l; j++) {
        var s2 = 0,
            s3 = 0;

        for (var i = 0; i < n; i++) {
          var dev = matrix[i][j] - means[j];
          s2 += dev * dev;
          s3 += dev * dev * dev;
        }

        var m2 = s2 / n;
        var m3 = s3 / n;
        var g = m3 / Math.pow(m2, 3 / 2);

        if (unbiased) {
          var a = Math.sqrt(n * (n - 1));
          var b = n - 2;
          skew[j] = a / b * g;
        } else {
          skew[j] = g;
        }
      }

      return skew;
    };

    exports.kurtosis = function kurtosis(matrix, unbiased) {
      if (typeof unbiased === 'undefined') unbiased = true;
      var means = exports.mean(matrix);
      var n = matrix.length,
          m = matrix[0].length;
      var kurt = new Array(m);

      for (var j = 0; j < m; j++) {
        var s2 = 0,
            s4 = 0;

        for (var i = 0; i < n; i++) {
          var dev = matrix[i][j] - means[j];
          s2 += dev * dev;
          s4 += dev * dev * dev * dev;
        }

        var m2 = s2 / n;
        var m4 = s4 / n;

        if (unbiased) {
          var v = s2 / (n - 1);
          var a = n * (n + 1) / ((n - 1) * (n - 2) * (n - 3));
          var b = s4 / (v * v);
          var c = (n - 1) * (n - 1) / ((n - 2) * (n - 3));
          kurt[j] = a * b - 3 * c;
        } else {
          kurt[j] = m4 / (m2 * m2) - 3;
        }
      }

      return kurt;
    };

    exports.standardError = function standardError(matrix) {
      var samples = matrix.length;
      var standardDeviations = exports.standardDeviation(matrix);
      var l = standardDeviations.length;
      var standardErrors = new Array(l);
      var sqrtN = Math.sqrt(samples);

      for (var i = 0; i < l; i++) {
        standardErrors[i] = standardDeviations[i] / sqrtN;
      }

      return standardErrors;
    };

    exports.covariance = function covariance(matrix, dimension) {
      return exports.scatter(matrix, undefined, dimension);
    };

    exports.scatter = function scatter(matrix, divisor, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      if (typeof divisor === 'undefined') {
        if (dimension === 0) {
          divisor = matrix.length - 1;
        } else if (dimension === 1) {
          divisor = matrix[0].length - 1;
        }
      }

      var means = exports.mean(matrix, dimension);
      var rows = matrix.length;

      if (rows === 0) {
        return [[]];
      }

      var cols = matrix[0].length,
          cov,
          i,
          j,
          s,
          k;

      if (dimension === 0) {
        cov = new Array(cols);

        for (i = 0; i < cols; i++) {
          cov[i] = new Array(cols);
        }

        for (i = 0; i < cols; i++) {
          for (j = i; j < cols; j++) {
            s = 0;

            for (k = 0; k < rows; k++) {
              s += (matrix[k][j] - means[j]) * (matrix[k][i] - means[i]);
            }

            s /= divisor;
            cov[i][j] = s;
            cov[j][i] = s;
          }
        }
      } else if (dimension === 1) {
        cov = new Array(rows);

        for (i = 0; i < rows; i++) {
          cov[i] = new Array(rows);
        }

        for (i = 0; i < rows; i++) {
          for (j = i; j < rows; j++) {
            s = 0;

            for (k = 0; k < cols; k++) {
              s += (matrix[j][k] - means[j]) * (matrix[i][k] - means[i]);
            }

            s /= divisor;
            cov[i][j] = s;
            cov[j][i] = s;
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return cov;
    };

    exports.correlation = function correlation(matrix) {
      var means = exports.mean(matrix),
          standardDeviations = exports.standardDeviation(matrix, true, means),
          scores = exports.zScores(matrix, means, standardDeviations),
          rows = matrix.length,
          cols = matrix[0].length,
          i,
          j;
      var cor = new Array(cols);

      for (i = 0; i < cols; i++) {
        cor[i] = new Array(cols);
      }

      for (i = 0; i < cols; i++) {
        for (j = i; j < cols; j++) {
          var c = 0;

          for (var k = 0, l = scores.length; k < l; k++) {
            c += scores[k][j] * scores[k][i];
          }

          c /= rows - 1;
          cor[i][j] = c;
          cor[j][i] = c;
        }
      }

      return cor;
    };

    exports.zScores = function zScores(matrix, means, standardDeviations) {
      means = means || exports.mean(matrix);
      if (typeof standardDeviations === 'undefined') standardDeviations = exports.standardDeviation(matrix, true, means);
      return exports.standardize(exports.center(matrix, means, false), standardDeviations, true);
    };

    exports.center = function center(matrix, means, inPlace) {
      means = means || exports.mean(matrix);
      var result = matrix,
          l = matrix.length,
          i,
          j,
          jj;

      if (!inPlace) {
        result = new Array(l);

        for (i = 0; i < l; i++) {
          result[i] = new Array(matrix[i].length);
        }
      }

      for (i = 0; i < l; i++) {
        var row = result[i];

        for (j = 0, jj = row.length; j < jj; j++) {
          row[j] = matrix[i][j] - means[j];
        }
      }

      return result;
    };

    exports.standardize = function standardize(matrix, standardDeviations, inPlace) {
      if (typeof standardDeviations === 'undefined') standardDeviations = exports.standardDeviation(matrix);
      var result = matrix,
          l = matrix.length,
          i,
          j,
          jj;

      if (!inPlace) {
        result = new Array(l);

        for (i = 0; i < l; i++) {
          result[i] = new Array(matrix[i].length);
        }
      }

      for (i = 0; i < l; i++) {
        var resultRow = result[i];
        var sourceRow = matrix[i];

        for (j = 0, jj = resultRow.length; j < jj; j++) {
          if (standardDeviations[j] !== 0 && !isNaN(standardDeviations[j])) {
            resultRow[j] = sourceRow[j] / standardDeviations[j];
          }
        }
      }

      return result;
    };

    exports.weightedVariance = function weightedVariance(matrix, weights) {
      var means = exports.mean(matrix);
      var rows = matrix.length;
      if (rows === 0) return [];
      var cols = matrix[0].length;
      var vari = new Array(cols);

      for (var j = 0; j < cols; j++) {
        var sum = 0;
        var a = 0,
            b = 0;

        for (var i = 0; i < rows; i++) {
          var z = matrix[i][j] - means[j];
          var w = weights[i];
          sum += w * (z * z);
          b += w;
          a += w * w;
        }

        vari[j] = sum * (b / (b * b - a));
      }

      return vari;
    };

    exports.weightedMean = function weightedMean(matrix, weights, dimension) {
      if (typeof dimension === 'undefined') {
        dimension = 0;
      }

      var rows = matrix.length;
      if (rows === 0) return [];
      var cols = matrix[0].length,
          means,
          i,
          ii,
          j,
          w,
          row;

      if (dimension === 0) {
        means = new Array(cols);

        for (i = 0; i < cols; i++) {
          means[i] = 0;
        }

        for (i = 0; i < rows; i++) {
          row = matrix[i];
          w = weights[i];

          for (j = 0; j < cols; j++) {
            means[j] += row[j] * w;
          }
        }
      } else if (dimension === 1) {
        means = new Array(rows);

        for (i = 0; i < rows; i++) {
          means[i] = 0;
        }

        for (j = 0; j < rows; j++) {
          row = matrix[j];
          w = weights[j];

          for (i = 0; i < cols; i++) {
            means[j] += row[i] * w;
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      var weightSum = array$2.sum(weights);

      if (weightSum !== 0) {
        for (i = 0, ii = means.length; i < ii; i++) {
          means[i] /= weightSum;
        }
      }

      return means;
    };

    exports.weightedCovariance = function weightedCovariance(matrix, weights, means, dimension) {
      dimension = dimension || 0;
      means = means || exports.weightedMean(matrix, weights, dimension);
      var s1 = 0,
          s2 = 0;

      for (var i = 0, ii = weights.length; i < ii; i++) {
        s1 += weights[i];
        s2 += weights[i] * weights[i];
      }

      var factor = s1 / (s1 * s1 - s2);
      return exports.weightedScatter(matrix, weights, means, factor, dimension);
    };

    exports.weightedScatter = function weightedScatter(matrix, weights, means, factor, dimension) {
      dimension = dimension || 0;
      means = means || exports.weightedMean(matrix, weights, dimension);

      if (typeof factor === 'undefined') {
        factor = 1;
      }

      var rows = matrix.length;

      if (rows === 0) {
        return [[]];
      }

      var cols = matrix[0].length,
          cov,
          i,
          j,
          k,
          s;

      if (dimension === 0) {
        cov = new Array(cols);

        for (i = 0; i < cols; i++) {
          cov[i] = new Array(cols);
        }

        for (i = 0; i < cols; i++) {
          for (j = i; j < cols; j++) {
            s = 0;

            for (k = 0; k < rows; k++) {
              s += weights[k] * (matrix[k][j] - means[j]) * (matrix[k][i] - means[i]);
            }

            cov[i][j] = s * factor;
            cov[j][i] = s * factor;
          }
        }
      } else if (dimension === 1) {
        cov = new Array(rows);

        for (i = 0; i < rows; i++) {
          cov[i] = new Array(rows);
        }

        for (i = 0; i < rows; i++) {
          for (j = i; j < rows; j++) {
            s = 0;

            for (k = 0; k < cols; k++) {
              s += weights[k] * (matrix[j][k] - means[j]) * (matrix[i][k] - means[i]);
            }

            cov[i][j] = s * factor;
            cov[j][i] = s * factor;
          }
        }
      } else {
        throw new Error('Invalid dimension');
      }

      return cov;
    };
  });

  var array$1 = array$2;
  var matrix = matrix$1;
  var mlStat = {
    array: array$1,
    matrix: matrix
  };

  var COMMON_NO = 0;
  var COMMON_FIRST = 1;
  var COMMON_SECOND = 2;
  var COMMON_BOTH = 3; // should be a binary operation !

  var Stat = mlStat.array;
  /**
   * Create a comparator class
   * {object} [options={}]
   * {string} [options.common=''] should we take only common peaks 'first', 'second', 'both', ''
   * {number} [options.widthBottom=2] bottom trapezoid width for similarity evaluation
   * {number} [options.widthTop=1] top trapezoid width for similarity evaluation
   * {number} [options.from] from region used for similarity calculation
   * {number} [options.to] to region used for similarity calculation
   */

  var src$4 = function Comparator(options = {}) {
    var widthTop, widthBottom, from, to;
    var array1Extract, array2Extract, widthSlope, array1ExtractInfo, array2ExtractInfo;
    var common, commonFactor;
    setOptions(options);
    var array1 = [];
    var array2 = [];
    /*
       2 formats are allowed:
       [[x1,x2,...],[y1,y2,...]] or [[x1,y1],[x2,y2], ...]
      */

    function setOptions(newOptions) {
      options = newOptions || {};

      if (typeof options.common === 'string') {
        if (options.common.toLowerCase() === 'first') {
          common = COMMON_FIRST;
        } else if (options.common.toLowerCase() === 'second') {
          common = COMMON_SECOND;
        } else if (options.common.toLowerCase() === 'both') {
          common = COMMON_BOTH;
        } else {
          common = COMMON_NO;
        }
      } else {
        if (options.common === true) {
          common = COMMON_BOTH;
        } else {
          common = COMMON_NO;
        }
      }

      commonFactor = options.commonFactor || commonFactor || 4;

      if (options.widthBottom === undefined) {
        options.widthBottom = widthBottom || 2;
      }

      if (options.widthTop === undefined) {
        options.widthTop = widthTop || 1;
      }

      setTrapezoid(options.widthBottom, options.widthTop);
      setFromTo(options.from || from, options.to || to);
    }

    function setPeaks1(anArray) {
      array1 = checkArray(anArray);

      if (common) {
        var extracts = commonExtractAndNormalize(array1, array2, widthBottom, from, to, common);
        array1Extract = extracts.data1;
        array1ExtractInfo = extracts.info1;
        array2Extract = extracts.data2;
        array2ExtractInfo = extracts.info2;
      } else {
        var extract = extractAndNormalize(array1, from, to);
        array1Extract = extract.data;
        array1ExtractInfo = extract.info;
      }
    }

    function setPeaks2(anArray) {
      array2 = checkArray(anArray);

      if (common) {
        var extracts = commonExtractAndNormalize(array1, array2, widthBottom, from, to, common);
        array1Extract = extracts.data1;
        array1ExtractInfo = extracts.info1;
        array2Extract = extracts.data2;
        array2ExtractInfo = extracts.info2;
      } else {
        var extract = extractAndNormalize(array2, from, to);
        array2Extract = extract.data;
        array2ExtractInfo = extract.info;
      }
    }

    function getExtract1() {
      return array1Extract;
    }

    function getExtract2() {
      return array2Extract;
    }

    function getExtractInfo1() {
      return array1ExtractInfo;
    }

    function getExtractInfo2() {
      return array2ExtractInfo;
    }

    function setTrapezoid(newWidthBottom, newWidthTop) {
      widthTop = newWidthTop;
      widthBottom = newWidthBottom;
      widthSlope = (widthBottom - widthTop) / 2;
      if (widthBottom < widthTop) throw new Error('widthBottom has to be larger than widthTop');
    }

    function setFromTo(newFrom, newTo) {
      if (newFrom === from && newTo === to) return;
      from = newFrom;
      to = newTo;

      if (common) {
        var extracts = commonExtractAndNormalize(array1, array2, widthBottom, from, to, common);
        array1Extract = extracts.data1;
        array1ExtractInfo = extracts.info1;
        array2Extract = extracts.data2;
        array2ExtractInfo = extracts.info2;
      } else {
        var extract = extractAndNormalize(array1, from, to);
        array1Extract = extract.data;
        array1ExtractInfo = extract.info;
        extract = extractAndNormalize(array2, from, to);
        array2Extract = extract.data;
        array2ExtractInfo = extract.info;
      }
    }

    function getOverlap(x1, y1, x2, y2) {
      if (y1 === 0 || y2 === 0) return 0; // TAKE CARE !!! We multiply the diff by 2 !!!

      var diff = Math.abs(x1 - x2) * 2;
      if (diff > widthBottom) return 0;

      if (diff <= widthTop) {
        return Math.min(y1, y2);
      }

      var maxValue = Math.max(y1, y2) * (widthBottom - diff) / (widthBottom - widthTop);
      return Math.min(y1, y2, maxValue);
    } // This is the old trapezoid similarity


    function getOverlapTrapezoid(x1, y1, x2, y2) {
      var factor = 2 / (widthTop + widthBottom); // correction for surface=1

      if (y1 === 0 || y2 === 0) return 0;

      if (x1 === x2) {
        // they have the same position
        return Math.min(y1, y2);
      }

      var diff = Math.abs(x1 - x2);
      if (diff >= widthBottom) return 0;

      if (y1 === y2) {
        // do they have the same height ???
        // we need to find the common length
        if (diff <= widthTop) {
          return ((widthTop + widthBottom) / 2 - diff) * y1 * factor;
        } else if (diff <= widthBottom) {
          return (widthBottom - diff) * y1 / 2 * (diff - widthTop) / (widthBottom - widthTop) * factor;
        }

        return 0;
      } else {
        // the height are different and not the same position ...
        // we need to consider only one segment to find its intersection
        var small = Math.min(y1, y2);
        var big = Math.max(y1, y2);
        var targets = [[[0, 0], [widthSlope, small]], [[widthSlope, small], [widthSlope + widthTop, small]], [[widthTop + widthSlope, small], [widthBottom, 0]]];
        var segment;

        if (x1 > x2 && y1 > y2 || x1 < x2 && y1 < y2) {
          segment = [[diff, 0], [diff + widthSlope, big]];
        } else {
          segment = [[diff + widthSlope, big], [diff, 0]];
        }

        for (var i = 0; i < 3; i++) {
          var intersection = getIntersection(targets[i], segment);

          if (intersection) {
            switch (i) {
              case 0:
                return small - diff * intersection.y / 2 * factor;

              case 1:
                // to simplify ...
                //     console.log("           ",widthSlope,small,big,intersection.x)
                return (widthSlope * small / (2 * big) * small + (widthTop + widthSlope - intersection.x) * small + widthSlope * small / 2) * factor;

              case 2:
                return (widthBottom - diff) * intersection.y / 2 * factor;

              default:
                throw new Error(`unexpected intersection value: ${i}`);
            }
          }
        }
      }

      return NaN;
    } // this method calculates the total diff. The sum of positive value will yield to overlap


    function calculateDiff() {
      // we need to take 2 pointers
      // and travel progressively between them ...
      var newFirst = [[].concat(array1Extract[0]), [].concat(array1Extract[1])];
      var newSecond = [[].concat(array2Extract[0]), [].concat(array2Extract[1])];
      var array1Length = array1Extract[0] ? array1Extract[0].length : 0;
      var array2Length = array2Extract[0] ? array2Extract[0].length : 0;
      var pos1 = 0;
      var pos2 = 0;
      var previous2 = 0;

      while (pos1 < array1Length) {
        var diff = newFirst[0][pos1] - array2Extract[0][pos2];

        if (Math.abs(diff) < widthBottom) {
          // there is some overlap
          var overlap;

          if (options.trapezoid) {
            overlap = getOverlapTrapezoid(newFirst[0][pos1], newFirst[1][pos1], newSecond[0][pos2], newSecond[1][pos2]);
          } else {
            overlap = getOverlap(newFirst[0][pos1], newFirst[1][pos1], newSecond[0][pos2], newSecond[1][pos2]);
          }

          newFirst[1][pos1] -= overlap;
          newSecond[1][pos2] -= overlap;

          if (pos2 < array2Length - 1) {
            pos2++;
          } else {
            pos1++;
            pos2 = previous2;
          }
        } else {
          if (diff > 0 && pos2 < array2Length - 1) {
            pos2++;
            previous2 = pos2;
          } else {
            pos1++;
            pos2 = previous2;
          }
        }
      }

      return newSecond;
    }
    /*
          This code requires the use of an array like  [[x1,y1],[x2,y2], ...]
          If it is not the right format, we will just convert it
          Otherwise we return the correct format
       */


    function checkArray(points) {
      // if it is already a 2D array of points, we just return them
      if (Array.isArray(points) && Array.isArray(points[0]) && points.length === 2) return points;
      var x = new Array(points.length);
      var y = new Array(points.length);

      for (var i = 0; i < points.length; i++) {
        x[i] = points[i][0];
        y[i] = points[i][1];
      }

      return [x, y];
    }

    function getSimilarity(newPeaks1, newPeaks2) {
      if (newPeaks1) setPeaks1(newPeaks1);
      if (newPeaks2) setPeaks2(newPeaks2);
      var result = {};
      result.diff = calculateDiff();
      result.extract1 = getExtract1();
      result.extract2 = getExtract2();
      result.extractInfo1 = getExtractInfo1();
      result.extractInfo2 = getExtractInfo2();
      result.similarity = calculateOverlapFromDiff(result.diff);
      result.widthBottom = widthBottom;
      result.widthTop = widthTop;
      return result;
    }
    /*
      This works mainly when you have a array1 that is fixed
      newPeaks2 have to be normalized ! (sum to 1)
    */


    function fastSimilarity(newPeaks2, from, to) {
      array1Extract = extract(array1, from, to);
      array2Extract = newPeaks2;
      if (common & COMMON_SECOND) array1Extract = getCommonArray(array1Extract, array2Extract, widthBottom);
      normalize$1(array1Extract);
      var diff = calculateDiff();
      return calculateOverlapFromDiff(diff);
    }

    this.setPeaks1 = setPeaks1;
    this.setPeaks2 = setPeaks2;
    this.getExtract1 = getExtract1;
    this.getExtract2 = getExtract2;
    this.getExtractInfo1 = getExtractInfo1;
    this.getExtractInfo2 = getExtractInfo2;
    this.setFromTo = setFromTo;
    this.setOptions = setOptions;
    this.setTrapezoid = setTrapezoid;
    this.getSimilarity = getSimilarity;
    this.getCommonArray = getCommonArray;
    this.fastSimilarity = fastSimilarity;
  }; // returns an new array based on array1 where there is a peak of array2 at a distance under width/2


  function getCommonArray(array1, array2, width) {
    var newArray = [[], []];
    var pos2 = 0;
    width /= 2;
    var j = 0;
    var array1Length = array1[0] ? array1[0].length : 0;
    var array2Length = array2[0] ? array2[0].length : 0;

    for (var i = 0; i < array1Length; i++) {
      while (pos2 < array2Length && array1[0][i] > array2[0][pos2] + width) {
        pos2++;
      }

      if (pos2 < array2Length && array1[0][i] > array2[0][pos2] - width) {
        newArray[0][j] = array1[0][i];
        newArray[1][j] = array1[1][i];
        j++;
      }
    }

    return newArray;
  } // Adapted from: http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/1968345#1968345


  function getIntersection(segment1, segment2) {
    var p0X = segment1[0][0];
    var p0Y = segment1[0][1];
    var p1X = segment1[1][0];
    var p1Y = segment1[1][1];
    var p2X = segment2[0][0];
    var p2Y = segment2[0][1];
    var p3X = segment2[1][0];
    var p3Y = segment2[1][1];
    var s1X, s1Y, s2X, s2Y;
    s1X = p1X - p0X;
    s1Y = p1Y - p0Y;
    s2X = p3X - p2X;
    s2Y = p3Y - p2Y;
    var s, t;
    s = (-s1Y * (p0X - p2X) + s1X * (p0Y - p2Y)) / (-s2X * s1Y + s1X * s2Y);
    t = (s2X * (p0Y - p2Y) - s2Y * (p0X - p2X)) / (-s2X * s1Y + s1X * s2Y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
      return {
        x: p0X + t * s1X,
        y: p0Y + t * s1Y
      };
    }

    return null; // No collision
  }

  function normalize$1(array) {
    var min = Stat.min(array[1]);
    var max = Stat.max(array[1]);
    var sum = Stat.sum(array[1]);
    var length = array[1] ? array[1].length : 0;

    if (sum !== 0) {
      for (var i = 0; i < length; i++) {
        array[1][i] /= sum;
      }
    }

    return {
      sum: sum,
      min: min,
      max: max
    };
  } // this method will systematically take care of both array


  function commonExtractAndNormalize(array1, array2, width, from, to, common) {
    if (!Array.isArray(array1) || !Array.isArray(array2)) {
      return {
        info: undefined,
        data: undefined
      };
    }

    var extract1 = extract(array1, from, to);
    var extract2 = extract(array2, from, to);
    var common1, common2, info1, info2;

    if (common & COMMON_SECOND) {
      common1 = getCommonArray(extract1, extract2, width);
      info1 = normalize$1(common1);
    } else {
      common1 = extract1;
      info1 = normalize$1(common1);
    }

    if (common & COMMON_FIRST) {
      common2 = getCommonArray(extract2, extract1, width);
      info2 = normalize$1(common2);
    } else {
      common2 = extract2;
      info2 = normalize$1(common2);
    }

    return {
      info1: info1,
      info2: info2,
      data1: common1,
      data2: common2
    };
  }

  function extract(array, from, to) {
    var newArray = [[], []];
    var j = 0;
    var length = array[0] ? array[0].length : 0;

    for (var i = 0; i < length; i++) {
      if ((!from || array[0][i] >= from) && (!to || array[0][i] <= to)) {
        newArray[0][j] = array[0][i];
        newArray[1][j] = array[1][i];
        j++;
      }
    }

    return newArray;
  }

  function extractAndNormalize(array, from, to) {
    if (!Array.isArray(array)) {
      return {
        info: undefined,
        data: undefined
      };
    }

    var newArray = extract(array, from, to);
    var info = normalize$1(newArray);
    return {
      info: info,
      data: newArray
    };
  }

  function calculateOverlapFromDiff(diffs) {
    if (diffs[1].length === 0) return 0;
    var sumPos = 0;

    for (var i = 0; i < diffs[1].length; i++) {
      sumPos += Math.abs(diffs[1][i]);
    }

    return 1 - sumPos;
  }

  /**
  Search for an experimental monoisotopic mass and calculate the similarity
  * @param {object}   [options={}]
  * @param {array}    [options.databases] - an array containing the name of the databases so search, by default all
  * @param {boolean}  [options.flatten] - should we return the array as a flat result
  * @param {string}   [options.ionizations=''] - Comma separated list of ionizations (to charge the molecule)
  * @param {object}   [options.minSimilarity=0.5] - min similarity value

  * @param {object}   [options.filter={}]
  * @param {boolean}  [options.filter.forceIonization=false] - If true ignore existing ionizations
  * @param {number}   [options.filter.msem] - Observed monoisotopic mass in mass spectrometer
  * @param {number}   [options.filter.precision=1000] - The precision on the experimental mass
  * @param {number}   [options.filter.minCharge=-Infinity] - Minimal charge
  * @param {number}   [options.filter.maxCharge=+Infinity] - Maximal charge
  * @param {object}   [options.filter.unsaturation={}}]
  * @param {number}   [options.filter.unsaturation.min=-Infinity] - Minimal unsaturation
  * @param {number}   [options.filter.unsaturation.max=+Infinity] - Maximal unsaturation
  * @param {number}   [options.filter.unsaturation.onlyInteger=false] - Integer unsaturation
  * @param {number}   [options.filter.unsaturation.onlyNonInteger=false] - Non integer unsaturation
  * @param {object}   [options.filter.atoms] - object of atom:{min, max}
  * @param {object}   [options.filter.callback] - a function to filter the MF
  * @param {object}   [options.similarity={}]
  * @param {object}   [options.similarity.widthBottom]
  * @param {object}   [options.similarity.widthTop]
  * @param {object}   [options.similarity.widthFunction] - function called with mass that should return an object width containing top and bottom
  * @param {object}   [options.similarity.zone={}]
  * @param {object}   [options.similarity.zone.low=-0.5] - window shift based on observed monoisotopic mass
  * @param {object}   [options.similarity.zone.high=2.5] - to value for the comparison window
  * @param {object}   [options.similarity.common]
  */


  var searchSimilarity = function searchSimilarity(options = {}) {
    const {
      similarity = {},
      minSimilarity = 0.5,
      filter = {}
    } = options;
    let width = {
      bottom: similarity.widthBottom,
      top: similarity.widthTop
    };

    if (!this.experimentalSpectrum || !this.experimentalSpectrum.data.x.length > 0) {
      throw Error('You need to add an experimental spectrum first using setMassSpectrum');
    }

    let experimentalData = this.experimentalSpectrum.data;
    let sumY = this.experimentalSpectrum.sumY(); // the result of this query will be stored in a property 'ms'

    let results = this.searchMSEM(filter.msem, options);
    let flatEntries = [];

    if (!options.flatten) {
      for (let database of Object.keys(results)) {
        for (let entry of results[database]) {
          flatEntries.push(entry);
        }
      }
    } else {
      flatEntries = results;
    }

    let {
      widthFunction,
      zone = {}
    } = similarity;

    if (widthFunction && typeof widthFunction === 'string') {
      // eslint-disable-next-line no-new-func
      widthFunction = new Function('mass', widthFunction);
      let checkTopBottom = widthFunction(123);

      if (!checkTopBottom.bottom || !checkTopBottom.top) {
        throw Error('widthFunction should return an object with bottom and top properties');
      }
    }

    const {
      low = -0.5,
      high = 2.5
    } = zone; // we need to calculate the similarity of the isotopic distribution

    let similarityProcessor = new src$4(similarity);
    similarityProcessor.setPeaks1([experimentalData.x, experimentalData.y]);

    for (let entry of flatEntries) {
      let isotopicDistribution = new src$5(entry.mf, {
        allowNeutral: false,
        ionizations: [entry.ionization]
      });
      let distribution = isotopicDistribution.getDistribution(); // we need to define the comparison zone that depends of the charge

      let from = entry.ms.em + low / Math.abs(entry.ms.charge);
      let to = entry.ms.em + high / Math.abs(entry.ms.charge);
      similarityProcessor.setFromTo(from, to);

      if (widthFunction) {
        width = widthFunction(entry.ms.em);
        similarityProcessor.setTrapezoid(width.bottom, width.top);
      }

      similarityProcessor.setPeaks2([distribution.xs, distribution.ys]);
      let result = similarityProcessor.getSimilarity();
      result.extractInfo1.from = from;
      result.extractInfo1.to = to;

      if (result.similarity > minSimilarity) {
        entry.ms.similarity = {
          value: result.similarity,
          experimental: result.extract1,
          theoretical: result.extract2,
          difference: result.diff,
          experimentalInfo: result.extractInfo1,
          thereoticalInfo: result.extractInfo2,
          quantity: result.extractInfo1.sum / sumY,
          width
        };
      }
    }

    if (!options.flatten) {
      for (let database of Object.keys(results)) {
        results[database] = results[database].filter(entry => entry.ms.similarity).sort((a, b) => b.ms.similarity.value - a.ms.similarity.value);

        for (let entry of results[database]) {
          flatEntries.push(entry);
        }
      }
    } else {
      results = results.filter(entry => entry.ms.similarity).sort((a, b) => b.ms.similarity.value - a.ms.similarity.value);
    }

    return results;
  };

  const {
    Spectrum
  } = src$k;

  function DBManager() {
    this.databases = {};
    this.experimentalSpectrum = undefined;
  }
  /**
   *
   * @param {*} data
   * @param {object} [options={}]
   * @param {number} [options.normed=true] Should we normed (sum Y to 1) the experimental spectrum ?
   */


  DBManager.prototype.setExperimentalSpectrum = function setExperimentalSpectrum(data, options = {}) {
    const {
      normed = true
    } = options;

    if (normed) {
      this.experimentalSpectrum = new Spectrum(data).normedY();
    } else {
      this.experimentalSpectrum = new Spectrum(data);
    }

    return this.experimentalSpectrum;
  };
  /**
   * Add a new database using the KnapSack content
   * @param {*} options
   */


  DBManager.prototype.loadKnapSack = async function loadKnapSack$1(options = {}) {
    const {
      databaseName = 'knapSack',
      forceReload = false
    } = options;
    if (this.databases[databaseName] && !forceReload) return;
    this.databases[databaseName] = await loadKnapSack();
  };
  /**
   * Add a new database of 12000 commercial products
   * @param {*} options
   */


  DBManager.prototype.loadCommercials = async function loadCommercials$1(options = {}) {
    const {
      databaseName = 'commercials',
      forceReload = false
    } = options;
    if (this.databases[databaseName] && !forceReload) return;
    this.databases[databaseName] = await loadCommercials();
  };

  DBManager.prototype.get = function get(databaseName) {
    return this.databases[databaseName];
  };
  /**
   * Load the contaminants databvase from a google sheet document
   * @param {*} options
   * @param {string} ['contaminants'] databaseName
   */


  DBManager.prototype.loadContaminants = async function loadContaminants(options = {}) {
    const {
      databaseName = 'contaminants',
      forceReload = false
    } = options;
    if (this.databases[databaseName] && !forceReload) return;
    this.databases[databaseName] = await loadGoogleSheet();
  };
  /**
   * Load a google sheet containin
   * @param {*} options
   * @param {string} ['sheet'] databaseName
   */


  DBManager.prototype.loadGoogleSheet = async function loadGoogleSheet$1(options = {}) {
    const {
      databaseName = 'sheet',
      forceReload = false
    } = options;
    if (this.databases[databaseName] && !forceReload) return;
    this.databases[databaseName] = await loadGoogleSheet();
  };

  DBManager.prototype.loadTest = function loadTest() {
    this.fromArray(['C1-100'], {
      databaseName: 'test',
      ionizations: '+'
    });
  };

  DBManager.prototype.loadNeutralTest = function loadNeutralTest(options = {}) {
    const {
      maxC = 100
    } = options;
    this.fromArray([`C1-${maxC}`], {
      databaseName: 'test'
    });
  };

  DBManager.prototype.fromMonoisotopicMass = function fromMonoisotopicMass$1(mass, options = {}) {
    const {
      databaseName = 'monoisotopic',
      append = false
    } = options;
    let result = fromMonoisotopicMass(mass, options);
    replaceOrAppend(this, databaseName, result.mfs, append);
    return result;
  };

  DBManager.prototype.fromArray = function fromArray$1(sequence, options = {}) {
    const {
      databaseName = 'generated',
      append = false,
      estimate
    } = options;
    const results = fromArray(sequence, options);
    if (estimate) return results;
    replaceOrAppend(this, databaseName, results, append);
  };

  DBManager.prototype.fromRange = function fromRange$1(sequence, options = {}) {
    const {
      databaseName = 'generated',
      append = false,
      estimate
    } = options;
    const results = fromRange(sequence, options);
    if (estimate) return results;
    replaceOrAppend(this, databaseName, results, append);
  };

  DBManager.prototype.fromPeptidicSequence = function fromPeptidicSequence$1(sequence, options = {}) {
    const {
      databaseName = 'peptidic',
      append = false,
      estimate
    } = options;
    const results = fromPeptidicSequence(sequence, options);
    if (estimate) return results;
    replaceOrAppend(this, databaseName, results, append);
  };

  DBManager.prototype.fromNucleicSequence = function fromNucleicSequence$1(sequence, options = {}) {
    const {
      databaseName = 'nucleic',
      append = false,
      estimate
    } = options;
    const results = fromNucleicSequence(sequence, options);
    if (estimate) return results;
    replaceOrAppend(this, databaseName, results, append);
  };

  DBManager.prototype.listDatabases = function listDatabases() {
    return Object.keys(this.databases).sort();
  };

  DBManager.prototype.getInfo = function getInfo() {
    return {
      databases: Object.keys(this.databases).sort().map(key => {
        return {
          name: key,
          nbEntries: this.databases[key].length
        };
      })
    };
  };

  DBManager.prototype.massShifts = massShifts_1;
  DBManager.prototype.search = search;
  DBManager.prototype.searchMSEM = searchMSEM;
  DBManager.prototype.searchPubchem = searchPubchem;
  DBManager.prototype.searchSimilarity = searchSimilarity;
  var src$3 = DBManager;

  function replaceOrAppend(emdb, databaseName, results, append = false) {
    if (!emdb.databases[databaseName] || !append) {
      emdb.databases[databaseName] = results;
      return;
    }

    emdb.databases[databaseName] = emdb.databases[databaseName].concat(results);
  }

  DBManager.Peptide = src$a;
  DBManager.Nucleotide = src$9;
  DBManager.MFParser = src$h;
  DBManager.IsotopicDistribution = src$5;

  function appendInternals(data) {
    // for each line (internal fragment) we calculate the vertical position
    // where it should be drawn as well and the maximal number of lines
    let maxNumberLines = 0;

    for (let result of data.results) {
      if (result.internal) {
        result.slot = assignSlot(result.from, result.to, data.residues.residues);
        if (result.slot > maxNumberLines) maxNumberLines = result.slot;
      }
    }

    for (let row of data.rows) {
      row.info.internals = maxNumberLines;
    }
  } // we need to define the height of the line.
  // we need to find a height that is not yet used.


  function assignSlot(from, to, residues) {
    let used = {};
    if (from > 0) from--; // we ensure that we don't put on the same line to sequences that are consecutive

    for (let i = from; i < to; i++) {
      let residue = residues[i];
      residue.paper.usedSlots.forEach(function (usedSlot, index) {
        used[index] = true;
      });
    }

    let counter = 0;

    while (true) {
      if (!used[counter]) {
        break;
      }

      counter++;
    }

    for (let i = from; i < to; i++) {
      residues[i].paper.usedSlots[counter] = true;
    }

    return counter;
  }

  var appendInternals_1 = appendInternals;

  const groups = src$b.getGroupsObject();
  const ALTERNATIVES = ['', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'];
  const SYMBOLS = ['Θ', 'Δ', 'Λ', 'Φ', 'Ω', 'Γ', 'Χ'];
  let currentSymbol = 0;
  /**
   * Code that allows to split a sequence of amino acids or nucleotides natural or non natural
   * @param {string} [sequence]
   * @param {object} [options={}]
   * @param {string} [options.kind] - peptide, rna, ds-dna or dna. Default if contains U: rna, otherwise ds-dna
   * @param {string} [options.fivePrime=monophosphate] - alcohol, monophosphate, diphosphate, triphosphate
   * @param {string} [options.circular=false]
   */

  var appendResidues = function appendResidues(data, sequence, options = {}) {
    const {
      kind = 'peptide'
    } = options;
    currentSymbol = 0; // we normalize the sequence to 3 letter codes

    if (kind === 'peptide') {
      sequence = src$a.sequenceToMF(sequence);
    } else {
      sequence = src$9.sequenceToMF(sequence, options);
    }

    const result = {
      begin: '',
      end: '',
      residues: []
    };
    const STATE_BEGIN = 0;
    const STATE_MIDDLE = 1;
    const STATE_END = 2;
    let parenthesisLevel = 0;
    let state = STATE_BEGIN; // as long as we don't have an uppercase followed by 2 lowercases

    for (let i = 0; i < sequence.length; i++) {
      let currentChar = sequence.charAt(i);
      let nextChar = i < sequence.length - 1 ? sequence.charAt(i + 1) : '';
      let nextNextChar = i < sequence.length - 2 ? sequence.charAt(i + 2) : '';

      if (state === STATE_BEGIN && currentChar.match(/[A-Z]/) && nextChar.match(/[a-z]/) && nextNextChar.match(/[a-z]/) && parenthesisLevel === 0) {
        state = STATE_MIDDLE;
      }

      if (state === STATE_MIDDLE && !sequence.substring(i).match(/[A-Z][a-z][a-z]/) && !currentChar.match(/[a-z]/) && parenthesisLevel === 0) {
        state = STATE_END;
      } else {
        if (currentChar.match(/[A-Z]/) && nextChar.match(/[a-z]/) && nextNextChar.match(/[a-z]/) && parenthesisLevel === 0) {
          result.residues.push('');
        }
      }

      switch (state) {
        case STATE_BEGIN:
          result.begin = result.begin + currentChar;
          break;

        case STATE_MIDDLE:
          result.residues[result.residues.length - 1] = result.residues[result.residues.length - 1] + currentChar;
          break;

        case STATE_END:
          result.end = result.end + currentChar;
          break;
      }

      if (currentChar === '(') {
        parenthesisLevel++;
      } else if (currentChar === ')') {
        parenthesisLevel--;
      }
    } // we process all the residues


    let alternatives = {};
    let replacements = {};

    for (let i = 0; i < result.residues.length; i++) {
      let label = result.residues[i];
      let residue = {
        value: label,
        results: {
          begin: [],
          end: []
        }
      };
      residue.fromBegin = i + 1;
      residue.fromEnd = result.residues.length - i;
      residue.kind = 'residue';

      if (label.includes('(')) {
        getModifiedReplacement(label, residue, alternatives, replacements);
      } else {
        if (groups[label] && groups[label].oneLetter) {
          residue.label = groups[label].oneLetter;
        } else {
          getUnknownReplacement(label, residue, replacements);
        }
      }

      result.residues[i] = residue;
    }

    result.begin = removeStartEndParenthesis(result.begin);
    result.end = removeStartEndParenthesis(result.end);

    if (result.begin.length > 2) {
      let label = options.kind === 'peptide' ? 'Nter' : "5'";
      replacements[result.begin] = {
        label
      };
      result.begin = label;
    }

    if (result.end.length > 2) {
      let label = options.kind === 'peptide' ? 'Cter' : "3'";
      replacements[result.begin] = {
        label
      };
      result.end = label;
    }

    result.begin = {
      label: result.begin,
      kind: 'begin'
    };
    result.end = {
      label: result.end,
      kind: 'end'
    };
    result.alternatives = alternatives;
    result.replacements = replacements;
    result.all = [result.begin].concat(result.residues, [result.end]);
    result.all.forEach(entry => {
      entry.info = {
        nbOver: 0,
        nbUnder: 0
      };
    });
    data.residues = result;
  };

  function getUnknownReplacement(unknownResidue, residue, replacements) {
    if (!replacements[unknownResidue]) {
      replacements[unknownResidue] = {
        label: SYMBOLS[currentSymbol] || '?',
        id: unknownResidue
      };
    }

    currentSymbol++;
    residue.replaced = true;
    residue.label = replacements[unknownResidue].label;
  }

  function getModifiedReplacement(modifiedResidue, residue, alternatives, replacements) {
    if (!replacements[modifiedResidue]) {
      let position = modifiedResidue.indexOf('(');
      let residueCode = modifiedResidue.substring(0, position);
      let modification = removeStartEndParenthesis(modifiedResidue.substring(position));

      if (groups[residueCode] && groups[residueCode].alternativeOneLetter) {
        let alternativeOneLetter = groups[residueCode].alternativeOneLetter;

        if (!alternatives[alternativeOneLetter]) {
          alternatives[alternativeOneLetter] = {
            count: 1
          };
        } else {
          alternatives[alternativeOneLetter].count++;
        }

        replacements[modifiedResidue] = {
          label: ALTERNATIVES[alternatives[alternativeOneLetter].count - 1] + alternativeOneLetter,
          residue: residueCode,
          modification
        };
      } else {
        getUnknownReplacement(modifiedResidue, residue, replacements);
      }
    }

    residue.replaced = true;
    residue.label = replacements[modifiedResidue].label;
  }

  function removeStartEndParenthesis(mf) {
    if (mf[0] === '(' && mf[mf.length - 1] === ')') {
      return mf.substring(1, mf.length - 1);
    }

    return mf;
  }

  /*!
  * @svgdotjs/svg.js - A lightweight library for manipulating and animating SVG.
  * @version 3.0.16
  * https://svgdotjs.github.io/
  *
  * @copyright Wout Fierens <wout@mick-wout.com>
  * @license MIT
  *
  * BUILT: Tue Nov 12 2019 21:57:16 GMT+0100 (GMT+01:00)
  */
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

  function createCommonjsModule(fn, module) {
    return module = {
      exports: {}
    }, fn(module, module.exports), module.exports;
  }

  var check = function (it) {
    return it && it.Math == Math && it;
  }; // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028


  var global_1 = // eslint-disable-next-line no-undef
  check(typeof globalThis == 'object' && globalThis) || check(typeof window == 'object' && window) || check(typeof self == 'object' && self) || check(typeof commonjsGlobal == 'object' && commonjsGlobal) || // eslint-disable-next-line no-new-func
  Function('return this')();

  var fails = function (exec) {
    try {
      return !!exec();
    } catch (error) {
      return true;
    }
  }; // Thank's IE8 for his funny defineProperty


  var descriptors = !fails(function () {
    return Object.defineProperty({}, 'a', {
      get: function () {
        return 7;
      }
    }).a != 7;
  });
  var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
  var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; // Nashorn ~ JDK8 bug

  var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({
    1: 2
  }, 1); // `Object.prototype.propertyIsEnumerable` method implementation
  // https://tc39.github.io/ecma262/#sec-object.prototype.propertyisenumerable

  var f = NASHORN_BUG ? function propertyIsEnumerable(V) {
    var descriptor = getOwnPropertyDescriptor(this, V);
    return !!descriptor && descriptor.enumerable;
  } : nativePropertyIsEnumerable;
  var objectPropertyIsEnumerable = {
    f: f
  };

  var createPropertyDescriptor = function (bitmap, value) {
    return {
      enumerable: !(bitmap & 1),
      configurable: !(bitmap & 2),
      writable: !(bitmap & 4),
      value: value
    };
  };

  var toString = {}.toString;

  var classofRaw = function (it) {
    return toString.call(it).slice(8, -1);
  };

  var split = ''.split; // fallback for non-array-like ES3 and non-enumerable old V8 strings

  var indexedObject = fails(function () {
    // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
    // eslint-disable-next-line no-prototype-builtins
    return !Object('z').propertyIsEnumerable(0);
  }) ? function (it) {
    return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
  } : Object; // `RequireObjectCoercible` abstract operation
  // https://tc39.github.io/ecma262/#sec-requireobjectcoercible

  var requireObjectCoercible = function (it) {
    if (it == undefined) throw TypeError("Can't call method on " + it);
    return it;
  }; // toObject with fallback for non-array-like ES3 strings


  var toIndexedObject = function (it) {
    return indexedObject(requireObjectCoercible(it));
  };

  var isObject = function (it) {
    return typeof it === 'object' ? it !== null : typeof it === 'function';
  }; // `ToPrimitive` abstract operation
  // https://tc39.github.io/ecma262/#sec-toprimitive
  // instead of the ES6 spec version, we didn't implement @@toPrimitive case
  // and the second argument - flag - preferred type is a string


  var toPrimitive = function (input, PREFERRED_STRING) {
    if (!isObject(input)) return input;
    var fn, val;
    if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
    if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
    if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
    throw TypeError("Can't convert object to primitive value");
  };

  var hasOwnProperty = {}.hasOwnProperty;

  var has = function (it, key) {
    return hasOwnProperty.call(it, key);
  };

  var document$1 = global_1.document; // typeof document.createElement is 'object' in old IE

  var EXISTS = isObject(document$1) && isObject(document$1.createElement);

  var documentCreateElement = function (it) {
    return EXISTS ? document$1.createElement(it) : {};
  }; // Thank's IE8 for his funny defineProperty


  var ie8DomDefine = !descriptors && !fails(function () {
    return Object.defineProperty(documentCreateElement('div'), 'a', {
      get: function () {
        return 7;
      }
    }).a != 7;
  });
  var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; // `Object.getOwnPropertyDescriptor` method
  // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor

  var f$1 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
    O = toIndexedObject(O);
    P = toPrimitive(P, true);
    if (ie8DomDefine) try {
      return nativeGetOwnPropertyDescriptor(O, P);
    } catch (error) {
      /* empty */
    }
    if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
  };
  var objectGetOwnPropertyDescriptor = {
    f: f$1
  };

  var anObject = function (it) {
    if (!isObject(it)) {
      throw TypeError(String(it) + ' is not an object');
    }

    return it;
  };

  var nativeDefineProperty = Object.defineProperty; // `Object.defineProperty` method
  // https://tc39.github.io/ecma262/#sec-object.defineproperty

  var f$2 = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
    anObject(O);
    P = toPrimitive(P, true);
    anObject(Attributes);
    if (ie8DomDefine) try {
      return nativeDefineProperty(O, P, Attributes);
    } catch (error) {
      /* empty */
    }
    if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
    if ('value' in Attributes) O[P] = Attributes.value;
    return O;
  };
  var objectDefineProperty = {
    f: f$2
  };
  var createNonEnumerableProperty = descriptors ? function (object, key, value) {
    return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
  } : function (object, key, value) {
    object[key] = value;
    return object;
  };

  var setGlobal = function (key, value) {
    try {
      createNonEnumerableProperty(global_1, key, value);
    } catch (error) {
      global_1[key] = value;
    }

    return value;
  };

  var SHARED = '__core-js_shared__';
  var store = global_1[SHARED] || setGlobal(SHARED, {});
  var sharedStore = store;
  var shared = createCommonjsModule(function (module) {
    (module.exports = function (key, value) {
      return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
    })('versions', []).push({
      version: '3.3.6',
      mode: 'global',
      copyright: '© 2019 Denis Pushkarev (zloirock.ru)'
    });
  });
  var functionToString = shared('native-function-to-string', Function.toString);
  var WeakMap = global_1.WeakMap;
  var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(functionToString.call(WeakMap));
  var id = 0;
  var postfix = Math.random();

  var uid = function (key) {
    return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
  };

  var keys = shared('keys');

  var sharedKey = function (key) {
    return keys[key] || (keys[key] = uid(key));
  };

  var hiddenKeys = {};
  var WeakMap$1 = global_1.WeakMap;
  var set, get, has$1;

  var enforce = function (it) {
    return has$1(it) ? get(it) : set(it, {});
  };

  var getterFor = function (TYPE) {
    return function (it) {
      var state;

      if (!isObject(it) || (state = get(it)).type !== TYPE) {
        throw TypeError('Incompatible receiver, ' + TYPE + ' required');
      }

      return state;
    };
  };

  if (nativeWeakMap) {
    var store$1 = new WeakMap$1();
    var wmget = store$1.get;
    var wmhas = store$1.has;
    var wmset = store$1.set;

    set = function (it, metadata) {
      wmset.call(store$1, it, metadata);
      return metadata;
    };

    get = function (it) {
      return wmget.call(store$1, it) || {};
    };

    has$1 = function (it) {
      return wmhas.call(store$1, it);
    };
  } else {
    var STATE = sharedKey('state');
    hiddenKeys[STATE] = true;

    set = function (it, metadata) {
      createNonEnumerableProperty(it, STATE, metadata);
      return metadata;
    };

    get = function (it) {
      return has(it, STATE) ? it[STATE] : {};
    };

    has$1 = function (it) {
      return has(it, STATE);
    };
  }

  var internalState = {
    set: set,
    get: get,
    has: has$1,
    enforce: enforce,
    getterFor: getterFor
  };
  var redefine = createCommonjsModule(function (module) {
    var getInternalState = internalState.get;
    var enforceInternalState = internalState.enforce;
    var TEMPLATE = String(functionToString).split('toString');
    shared('inspectSource', function (it) {
      return functionToString.call(it);
    });
    (module.exports = function (O, key, value, options) {
      var unsafe = options ? !!options.unsafe : false;
      var simple = options ? !!options.enumerable : false;
      var noTargetGet = options ? !!options.noTargetGet : false;

      if (typeof value == 'function') {
        if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key);
        enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
      }

      if (O === global_1) {
        if (simple) O[key] = value;else setGlobal(key, value);
        return;
      } else if (!unsafe) {
        delete O[key];
      } else if (!noTargetGet && O[key]) {
        simple = true;
      }

      if (simple) O[key] = value;else createNonEnumerableProperty(O, key, value); // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
    })(Function.prototype, 'toString', function toString() {
      return typeof this == 'function' && getInternalState(this).source || functionToString.call(this);
    });
  });
  var path = global_1;

  var aFunction = function (variable) {
    return typeof variable == 'function' ? variable : undefined;
  };

  var getBuiltIn = function (namespace, method) {
    return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace]) : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
  };

  var ceil = Math.ceil;
  var floor = Math.floor; // `ToInteger` abstract operation
  // https://tc39.github.io/ecma262/#sec-tointeger

  var toInteger = function (argument) {
    return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
  };

  var min = Math.min; // `ToLength` abstract operation
  // https://tc39.github.io/ecma262/#sec-tolength

  var toLength = function (argument) {
    return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
  };

  var max = Math.max;
  var min$1 = Math.min; // Helper for a popular repeating case of the spec:
  // Let integer be ? ToInteger(index).
  // If integer < 0, let result be max((length + integer), 0); else let result be min(length, length).

  var toAbsoluteIndex = function (index, length) {
    var integer = toInteger(index);
    return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
  }; // `Array.prototype.{ indexOf, includes }` methods implementation


  var createMethod = function (IS_INCLUDES) {
    return function ($this, el, fromIndex) {
      var O = toIndexedObject($this);
      var length = toLength(O.length);
      var index = toAbsoluteIndex(fromIndex, length);
      var value; // Array#includes uses SameValueZero equality algorithm
      // eslint-disable-next-line no-self-compare

      if (IS_INCLUDES && el != el) while (length > index) {
        value = O[index++]; // eslint-disable-next-line no-self-compare

        if (value != value) return true; // Array#indexOf ignores holes, Array#includes - not
      } else for (; length > index; index++) {
        if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
      }
      return !IS_INCLUDES && -1;
    };
  };

  var arrayIncludes = {
    // `Array.prototype.includes` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.includes
    includes: createMethod(true),
    // `Array.prototype.indexOf` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.indexof
    indexOf: createMethod(false)
  };
  var indexOf = arrayIncludes.indexOf;

  var objectKeysInternal = function (object, names) {
    var O = toIndexedObject(object);
    var i = 0;
    var result = [];
    var key;

    for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key); // Don't enum bug & hidden keys


    while (names.length > i) if (has(O, key = names[i++])) {
      ~indexOf(result, key) || result.push(key);
    }

    return result;
  }; // IE8- don't enum bug keys


  var enumBugKeys = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];
  var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype'); // `Object.getOwnPropertyNames` method
  // https://tc39.github.io/ecma262/#sec-object.getownpropertynames

  var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
    return objectKeysInternal(O, hiddenKeys$1);
  };

  var objectGetOwnPropertyNames = {
    f: f$3
  };
  var f$4 = Object.getOwnPropertySymbols;
  var objectGetOwnPropertySymbols = {
    f: f$4
  }; // all object keys, includes non-enumerable and symbols

  var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
    var keys = objectGetOwnPropertyNames.f(anObject(it));
    var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
    return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
  };

  var copyConstructorProperties = function (target, source) {
    var keys = ownKeys(source);
    var defineProperty = objectDefineProperty.f;
    var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;

    for (var i = 0; i < keys.length; i++) {
      var key = keys[i];
      if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
    }
  };

  var replacement = /#|\.prototype\./;

  var isForced = function (feature, detection) {
    var value = data[normalize(feature)];
    return value == POLYFILL ? true : value == NATIVE ? false : typeof detection == 'function' ? fails(detection) : !!detection;
  };

  var normalize = isForced.normalize = function (string) {
    return String(string).replace(replacement, '.').toLowerCase();
  };

  var data = isForced.data = {};
  var NATIVE = isForced.NATIVE = 'N';
  var POLYFILL = isForced.POLYFILL = 'P';
  var isForced_1 = isForced;
  var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
  /*
    options.target      - name of the target object
    options.global      - target is the global object
    options.stat        - export as static methods of target
    options.proto       - export as prototype methods of target
    options.real        - real prototype method for the `pure` version
    options.forced      - export even if the native feature is available
    options.bind        - bind methods to the target, required for the `pure` version
    options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
    options.unsafe      - use the simple assignment of property instead of delete + defineProperty
    options.sham        - add a flag to not completely full polyfills
    options.enumerable  - export as enumerable property
    options.noTargetGet - prevent calling a getter on target
  */

  var _export = function (options, source) {
    var TARGET = options.target;
    var GLOBAL = options.global;
    var STATIC = options.stat;
    var FORCED, target, key, targetProperty, sourceProperty, descriptor;

    if (GLOBAL) {
      target = global_1;
    } else if (STATIC) {
      target = global_1[TARGET] || setGlobal(TARGET, {});
    } else {
      target = (global_1[TARGET] || {}).prototype;
    }

    if (target) for (key in source) {
      sourceProperty = source[key];

      if (options.noTargetGet) {
        descriptor = getOwnPropertyDescriptor$1(target, key);
        targetProperty = descriptor && descriptor.value;
      } else targetProperty = target[key];

      FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); // contained in target

      if (!FORCED && targetProperty !== undefined) {
        if (typeof sourceProperty === typeof targetProperty) continue;
        copyConstructorProperties(sourceProperty, targetProperty);
      } // add a flag to not completely full polyfills


      if (options.sham || targetProperty && targetProperty.sham) {
        createNonEnumerableProperty(sourceProperty, 'sham', true);
      } // extend global


      redefine(target, key, sourceProperty, options);
    }
  }; // `IsArray` abstract operation
  // https://tc39.github.io/ecma262/#sec-isarray


  var isArray = Array.isArray || function isArray(arg) {
    return classofRaw(arg) == 'Array';
  };

  var createProperty = function (object, key, value) {
    var propertyKey = toPrimitive(key);
    if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));else object[propertyKey] = value;
  };

  var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
    // Chrome 38 Symbol has incorrect toString conversion
    // eslint-disable-next-line no-undef
    return !String(Symbol());
  });
  var Symbol$1 = global_1.Symbol;
  var store$2 = shared('wks');

  var wellKnownSymbol = function (name) {
    return store$2[name] || (store$2[name] = nativeSymbol && Symbol$1[name] || (nativeSymbol ? Symbol$1 : uid)('Symbol.' + name));
  };

  var userAgent = getBuiltIn('navigator', 'userAgent') || '';
  var process = global_1.process;
  var versions = process && process.versions;
  var v8 = versions && versions.v8;
  var match, version;

  if (v8) {
    match = v8.split('.');
    version = match[0] + match[1];
  } else if (userAgent) {
    match = userAgent.match(/Edge\/(\d+)/);

    if (!match || match[1] >= 74) {
      match = userAgent.match(/Chrome\/(\d+)/);
      if (match) version = match[1];
    }
  }

  var v8Version = version && +version;
  var SPECIES = wellKnownSymbol('species');

  var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
    // We can't use this feature detection in V8 since it causes
    // deoptimization and serious performance degradation
    // https://github.com/zloirock/core-js/issues/677
    return v8Version >= 51 || !fails(function () {
      var array = [];
      var constructor = array.constructor = {};

      constructor[SPECIES] = function () {
        return {
          foo: 1
        };
      };

      return array[METHOD_NAME](Boolean).foo !== 1;
    });
  };

  var SPECIES$1 = wellKnownSymbol('species');
  var nativeSlice = [].slice;
  var max$1 = Math.max; // `Array.prototype.slice` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.slice
  // fallback for not array-like ES3 strings and DOM objects

  _export({
    target: 'Array',
    proto: true,
    forced: !arrayMethodHasSpeciesSupport('slice')
  }, {
    slice: function slice(start, end) {
      var O = toIndexedObject(this);
      var length = toLength(O.length);
      var k = toAbsoluteIndex(start, length);
      var fin = toAbsoluteIndex(end === undefined ? length : end, length); // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible

      var Constructor, result, n;

      if (isArray(O)) {
        Constructor = O.constructor; // cross-realm fallback

        if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) {
          Constructor = undefined;
        } else if (isObject(Constructor)) {
          Constructor = Constructor[SPECIES$1];
          if (Constructor === null) Constructor = undefined;
        }

        if (Constructor === Array || Constructor === undefined) {
          return nativeSlice.call(O, k, fin);
        }
      }

      result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0));

      for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]);

      result.length = n;
      return result;
    }
  });

  var defineProperty = objectDefineProperty.f;
  var FunctionPrototype = Function.prototype;
  var FunctionPrototypeToString = FunctionPrototype.toString;
  var nameRE = /^\s*function ([^ (]*)/;
  var NAME = 'name'; // Function instances `.name` property
  // https://tc39.github.io/ecma262/#sec-function-instances-name

  if (descriptors && !(NAME in FunctionPrototype)) {
    defineProperty(FunctionPrototype, NAME, {
      configurable: true,
      get: function () {
        try {
          return FunctionPrototypeToString.call(this).match(nameRE)[1];
        } catch (error) {
          return '';
        }
      }
    });
  }

  var nativeGetOwnPropertyNames = objectGetOwnPropertyNames.f;
  var toString$1 = {}.toString;
  var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : [];

  var getWindowNames = function (it) {
    try {
      return nativeGetOwnPropertyNames(it);
    } catch (error) {
      return windowNames.slice();
    }
  }; // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window


  var f$5 = function getOwnPropertyNames(it) {
    return windowNames && toString$1.call(it) == '[object Window]' ? getWindowNames(it) : nativeGetOwnPropertyNames(toIndexedObject(it));
  };

  var objectGetOwnPropertyNamesExternal = {
    f: f$5
  };
  var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f;
  var FAILS_ON_PRIMITIVES = fails(function () {
    return !Object.getOwnPropertyNames(1);
  }); // `Object.getOwnPropertyNames` method
  // https://tc39.github.io/ecma262/#sec-object.getownpropertynames

  _export({
    target: 'Object',
    stat: true,
    forced: FAILS_ON_PRIMITIVES
  }, {
    getOwnPropertyNames: nativeGetOwnPropertyNames$1
  });

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

    return _typeof2(obj);
  }

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

    return _typeof(obj);
  } // `ToObject` abstract operation
  // https://tc39.github.io/ecma262/#sec-toobject


  var toObject = function (argument) {
    return Object(requireObjectCoercible(argument));
  }; // `Object.keys` method
  // https://tc39.github.io/ecma262/#sec-object.keys


  var objectKeys = Object.keys || function keys(O) {
    return objectKeysInternal(O, enumBugKeys);
  }; // `Object.defineProperties` method
  // https://tc39.github.io/ecma262/#sec-object.defineproperties


  var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
    anObject(O);
    var keys = objectKeys(Properties);
    var length = keys.length;
    var index = 0;
    var key;

    while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);

    return O;
  };
  var html = getBuiltIn('document', 'documentElement');
  var IE_PROTO = sharedKey('IE_PROTO');
  var PROTOTYPE = 'prototype';

  var Empty = function () {
    /* empty */
  }; // Create object with fake `null` prototype: use iframe Object with cleared prototype


  var createDict = function () {
    // Thrash, waste and sodomy: IE GC bug
    var iframe = documentCreateElement('iframe');
    var length = enumBugKeys.length;
    var lt = '<';
    var script = 'script';
    var gt = '>';
    var js = 'java' + script + ':';
    var iframeDocument;
    iframe.style.display = 'none';
    html.appendChild(iframe);
    iframe.src = String(js);
    iframeDocument = iframe.contentWindow.document;
    iframeDocument.open();
    iframeDocument.write(lt + script + gt + 'document.F=Object' + lt + '/' + script + gt);
    iframeDocument.close();
    createDict = iframeDocument.F;

    while (length--) delete createDict[PROTOTYPE][enumBugKeys[length]];

    return createDict();
  }; // `Object.create` method
  // https://tc39.github.io/ecma262/#sec-object.create


  var objectCreate = Object.create || function create(O, Properties) {
    var result;

    if (O !== null) {
      Empty[PROTOTYPE] = anObject(O);
      result = new Empty();
      Empty[PROTOTYPE] = null; // add "__proto__" for Object.getPrototypeOf polyfill

      result[IE_PROTO] = O;
    } else result = createDict();

    return Properties === undefined ? result : objectDefineProperties(result, Properties);
  };

  hiddenKeys[IE_PROTO] = true;
  var f$6 = wellKnownSymbol;
  var wrappedWellKnownSymbol = {
    f: f$6
  };
  var defineProperty$1 = objectDefineProperty.f;

  var defineWellKnownSymbol = function (NAME) {
    var Symbol = path.Symbol || (path.Symbol = {});
    if (!has(Symbol, NAME)) defineProperty$1(Symbol, NAME, {
      value: wrappedWellKnownSymbol.f(NAME)
    });
  };

  var defineProperty$2 = objectDefineProperty.f;
  var TO_STRING_TAG = wellKnownSymbol('toStringTag');

  var setToStringTag = function (it, TAG, STATIC) {
    if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG)) {
      defineProperty$2(it, TO_STRING_TAG, {
        configurable: true,
        value: TAG
      });
    }
  };

  var aFunction$1 = function (it) {
    if (typeof it != 'function') {
      throw TypeError(String(it) + ' is not a function');
    }

    return it;
  }; // optional / simple context binding


  var bindContext = function (fn, that, length) {
    aFunction$1(fn);
    if (that === undefined) return fn;

    switch (length) {
      case 0:
        return function () {
          return fn.call(that);
        };

      case 1:
        return function (a) {
          return fn.call(that, a);
        };

      case 2:
        return function (a, b) {
          return fn.call(that, a, b);
        };

      case 3:
        return function (a, b, c) {
          return fn.call(that, a, b, c);
        };
    }

    return function ()
    /* ...args */
    {
      return fn.apply(that, arguments);
    };
  };

  var SPECIES$2 = wellKnownSymbol('species'); // `ArraySpeciesCreate` abstract operation
  // https://tc39.github.io/ecma262/#sec-arrayspeciescreate

  var arraySpeciesCreate = function (originalArray, length) {
    var C;

    if (isArray(originalArray)) {
      C = originalArray.constructor; // cross-realm fallback

      if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;else if (isObject(C)) {
        C = C[SPECIES$2];
        if (C === null) C = undefined;
      }
    }

    return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
  };

  var push = [].push; // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex }` methods implementation

  var createMethod$1 = function (TYPE) {
    var IS_MAP = TYPE == 1;
    var IS_FILTER = TYPE == 2;
    var IS_SOME = TYPE == 3;
    var IS_EVERY = TYPE == 4;
    var IS_FIND_INDEX = TYPE == 6;
    var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
    return function ($this, callbackfn, that, specificCreate) {
      var O = toObject($this);
      var self = indexedObject(O);
      var boundFunction = bindContext(callbackfn, that, 3);
      var length = toLength(self.length);
      var index = 0;
      var create = specificCreate || arraySpeciesCreate;
      var target = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined;
      var value, result;

      for (; length > index; index++) if (NO_HOLES || index in self) {
        value = self[index];
        result = boundFunction(value, index, O);

        if (TYPE) {
          if (IS_MAP) target[index] = result; // map
          else if (result) switch (TYPE) {
              case 3:
                return true;
              // some

              case 5:
                return value;
              // find

              case 6:
                return index;
              // findIndex

              case 2:
                push.call(target, value);
              // filter
            } else if (IS_EVERY) return false; // every
        }
      }

      return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
    };
  };

  var arrayIteration = {
    // `Array.prototype.forEach` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
    forEach: createMethod$1(0),
    // `Array.prototype.map` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.map
    map: createMethod$1(1),
    // `Array.prototype.filter` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.filter
    filter: createMethod$1(2),
    // `Array.prototype.some` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.some
    some: createMethod$1(3),
    // `Array.prototype.every` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.every
    every: createMethod$1(4),
    // `Array.prototype.find` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.find
    find: createMethod$1(5),
    // `Array.prototype.findIndex` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
    findIndex: createMethod$1(6)
  };
  var $forEach = arrayIteration.forEach;
  var HIDDEN = sharedKey('hidden');
  var SYMBOL = 'Symbol';
  var PROTOTYPE$1 = 'prototype';
  var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
  var setInternalState = internalState.set;
  var getInternalState = internalState.getterFor(SYMBOL);
  var ObjectPrototype = Object[PROTOTYPE$1];
  var $Symbol = global_1.Symbol;
  var JSON$1 = global_1.JSON;
  var nativeJSONStringify = JSON$1 && JSON$1.stringify;
  var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
  var nativeDefineProperty$1 = objectDefineProperty.f;
  var nativeGetOwnPropertyNames$2 = objectGetOwnPropertyNamesExternal.f;
  var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f;
  var AllSymbols = shared('symbols');
  var ObjectPrototypeSymbols = shared('op-symbols');
  var StringToSymbolRegistry = shared('string-to-symbol-registry');
  var SymbolToStringRegistry = shared('symbol-to-string-registry');
  var WellKnownSymbolsStore = shared('wks');
  var QObject = global_1.QObject; // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173

  var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild; // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687

  var setSymbolDescriptor = descriptors && fails(function () {
    return objectCreate(nativeDefineProperty$1({}, 'a', {
      get: function () {
        return nativeDefineProperty$1(this, 'a', {
          value: 7
        }).a;
      }
    })).a != 7;
  }) ? function (O, P, Attributes) {
    var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype, P);
    if (ObjectPrototypeDescriptor) delete ObjectPrototype[P];
    nativeDefineProperty$1(O, P, Attributes);

    if (ObjectPrototypeDescriptor && O !== ObjectPrototype) {
      nativeDefineProperty$1(ObjectPrototype, P, ObjectPrototypeDescriptor);
    }
  } : nativeDefineProperty$1;

  var wrap = function (tag, description) {
    var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE$1]);
    setInternalState(symbol, {
      type: SYMBOL,
      tag: tag,
      description: description
    });
    if (!descriptors) symbol.description = description;
    return symbol;
  };

  var isSymbol = nativeSymbol && typeof $Symbol.iterator == 'symbol' ? function (it) {
    return typeof it == 'symbol';
  } : function (it) {
    return Object(it) instanceof $Symbol;
  };

  var $defineProperty = function defineProperty(O, P, Attributes) {
    if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
    anObject(O);
    var key = toPrimitive(P, true);
    anObject(Attributes);

    if (has(AllSymbols, key)) {
      if (!Attributes.enumerable) {
        if (!has(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor(1, {}));
        O[HIDDEN][key] = true;
      } else {
        if (has(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
        Attributes = objectCreate(Attributes, {
          enumerable: createPropertyDescriptor(0, false)
        });
      }

      return setSymbolDescriptor(O, key, Attributes);
    }

    return nativeDefineProperty$1(O, key, Attributes);
  };

  var $defineProperties = function defineProperties(O, Properties) {
    anObject(O);
    var properties = toIndexedObject(Properties);
    var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties));
    $forEach(keys, function (key) {
      if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
    });
    return O;
  };

  var $create = function create(O, Properties) {
    return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties);
  };

  var $propertyIsEnumerable = function propertyIsEnumerable(V) {
    var P = toPrimitive(V, true);
    var enumerable = nativePropertyIsEnumerable$1.call(this, P);
    if (this === ObjectPrototype && has(AllSymbols, P) && !has(ObjectPrototypeSymbols, P)) return false;
    return enumerable || !has(this, P) || !has(AllSymbols, P) || has(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
  };

  var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
    var it = toIndexedObject(O);
    var key = toPrimitive(P, true);
    if (it === ObjectPrototype && has(AllSymbols, key) && !has(ObjectPrototypeSymbols, key)) return;
    var descriptor = nativeGetOwnPropertyDescriptor$1(it, key);

    if (descriptor && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) {
      descriptor.enumerable = true;
    }

    return descriptor;
  };

  var $getOwnPropertyNames = function getOwnPropertyNames(O) {
    var names = nativeGetOwnPropertyNames$2(toIndexedObject(O));
    var result = [];
    $forEach(names, function (key) {
      if (!has(AllSymbols, key) && !has(hiddenKeys, key)) result.push(key);
    });
    return result;
  };

  var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
    var IS_OBJECT_PROTOTYPE = O === ObjectPrototype;
    var names = nativeGetOwnPropertyNames$2(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O));
    var result = [];
    $forEach(names, function (key) {
      if (has(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype, key))) {
        result.push(AllSymbols[key]);
      }
    });
    return result;
  }; // `Symbol` constructor
  // https://tc39.github.io/ecma262/#sec-symbol-constructor


  if (!nativeSymbol) {
    $Symbol = function Symbol() {
      if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
      var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
      var tag = uid(description);

      var setter = function (value) {
        if (this === ObjectPrototype) setter.call(ObjectPrototypeSymbols, value);
        if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
        setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value));
      };

      if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, {
        configurable: true,
        set: setter
      });
      return wrap(tag, description);
    };

    redefine($Symbol[PROTOTYPE$1], 'toString', function toString() {
      return getInternalState(this).tag;
    });
    objectPropertyIsEnumerable.f = $propertyIsEnumerable;
    objectDefineProperty.f = $defineProperty;
    objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor;
    objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames;
    objectGetOwnPropertySymbols.f = $getOwnPropertySymbols;

    if (descriptors) {
      // https://github.com/tc39/proposal-Symbol-description
      nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', {
        configurable: true,
        get: function description() {
          return getInternalState(this).description;
        }
      });
      {
        redefine(ObjectPrototype, 'propertyIsEnumerable', $propertyIsEnumerable, {
          unsafe: true
        });
      }
    }

    wrappedWellKnownSymbol.f = function (name) {
      return wrap(wellKnownSymbol(name), name);
    };
  }

  _export({
    global: true,
    wrap: true,
    forced: !nativeSymbol,
    sham: !nativeSymbol
  }, {
    Symbol: $Symbol
  });

  $forEach(objectKeys(WellKnownSymbolsStore), function (name) {
    defineWellKnownSymbol(name);
  });

  _export({
    target: SYMBOL,
    stat: true,
    forced: !nativeSymbol
  }, {
    // `Symbol.for` method
    // https://tc39.github.io/ecma262/#sec-symbol.for
    'for': function (key) {
      var string = String(key);
      if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
      var symbol = $Symbol(string);
      StringToSymbolRegistry[string] = symbol;
      SymbolToStringRegistry[symbol] = string;
      return symbol;
    },
    // `Symbol.keyFor` method
    // https://tc39.github.io/ecma262/#sec-symbol.keyfor
    keyFor: function keyFor(sym) {
      if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol');
      if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
    },
    useSetter: function () {
      USE_SETTER = true;
    },
    useSimple: function () {
      USE_SETTER = false;
    }
  });

  _export({
    target: 'Object',
    stat: true,
    forced: !nativeSymbol,
    sham: !descriptors
  }, {
    // `Object.create` method
    // https://tc39.github.io/ecma262/#sec-object.create
    create: $create,
    // `Object.defineProperty` method
    // https://tc39.github.io/ecma262/#sec-object.defineproperty
    defineProperty: $defineProperty,
    // `Object.defineProperties` method
    // https://tc39.github.io/ecma262/#sec-object.defineproperties
    defineProperties: $defineProperties,
    // `Object.getOwnPropertyDescriptor` method
    // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors
    getOwnPropertyDescriptor: $getOwnPropertyDescriptor
  });

  _export({
    target: 'Object',
    stat: true,
    forced: !nativeSymbol
  }, {
    // `Object.getOwnPropertyNames` method
    // https://tc39.github.io/ecma262/#sec-object.getownpropertynames
    getOwnPropertyNames: $getOwnPropertyNames,
    // `Object.getOwnPropertySymbols` method
    // https://tc39.github.io/ecma262/#sec-object.getownpropertysymbols
    getOwnPropertySymbols: $getOwnPropertySymbols
  }); // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
  // https://bugs.chromium.org/p/v8/issues/detail?id=3443


  _export({
    target: 'Object',
    stat: true,
    forced: fails(function () {
      objectGetOwnPropertySymbols.f(1);
    })
  }, {
    getOwnPropertySymbols: function getOwnPropertySymbols(it) {
      return objectGetOwnPropertySymbols.f(toObject(it));
    }
  }); // `JSON.stringify` method behavior with symbols
  // https://tc39.github.io/ecma262/#sec-json.stringify


  JSON$1 && _export({
    target: 'JSON',
    stat: true,
    forced: !nativeSymbol || fails(function () {
      var symbol = $Symbol(); // MS Edge converts symbol values to JSON as {}

      return nativeJSONStringify([symbol]) != '[null]' // WebKit converts symbol values to JSON as null
      || nativeJSONStringify({
        a: symbol
      }) != '{}' // V8 throws on boxed symbols
      || nativeJSONStringify(Object(symbol)) != '{}';
    })
  }, {
    stringify: function stringify(it) {
      var args = [it];
      var index = 1;
      var replacer, $replacer;

      while (arguments.length > index) args.push(arguments[index++]);

      $replacer = replacer = args[1];
      if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined

      if (!isArray(replacer)) replacer = function (key, value) {
        if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
        if (!isSymbol(value)) return value;
      };
      args[1] = replacer;
      return nativeJSONStringify.apply(JSON$1, args);
    }
  }); // `Symbol.prototype[@@toPrimitive]` method
  // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@toprimitive

  if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) {
    createNonEnumerableProperty($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf);
  } // `Symbol.prototype[@@toStringTag]` property
  // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@tostringtag


  setToStringTag($Symbol, SYMBOL);
  hiddenKeys[HIDDEN] = true;
  var defineProperty$3 = objectDefineProperty.f;
  var NativeSymbol = global_1.Symbol;

  if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) || // Safari 12 bug
  NativeSymbol().description !== undefined)) {
    var EmptyStringDescriptionStore = {}; // wrap Symbol constructor for correct work with undefined description

    var SymbolWrapper = function Symbol() {
      var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
      var result = this instanceof SymbolWrapper ? new NativeSymbol(description) // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
      : description === undefined ? NativeSymbol() : NativeSymbol(description);
      if (description === '') EmptyStringDescriptionStore[result] = true;
      return result;
    };

    copyConstructorProperties(SymbolWrapper, NativeSymbol);
    var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
    symbolPrototype.constructor = SymbolWrapper;
    var symbolToString = symbolPrototype.toString;
    var native = String(NativeSymbol('test')) == 'Symbol(test)';
    var regexp = /^Symbol\((.*)\)[^)]+$/;
    defineProperty$3(symbolPrototype, 'description', {
      configurable: true,
      get: function description() {
        var symbol = isObject(this) ? this.valueOf() : this;
        var string = symbolToString.call(symbol);
        if (has(EmptyStringDescriptionStore, symbol)) return '';
        var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
        return desc === '' ? undefined : desc;
      }
    });

    _export({
      global: true,
      forced: true
    }, {
      Symbol: SymbolWrapper
    });
  } // `Symbol.iterator` well-known symbol
  // https://tc39.github.io/ecma262/#sec-symbol.iterator


  defineWellKnownSymbol('iterator');
  var UNSCOPABLES = wellKnownSymbol('unscopables');
  var ArrayPrototype = Array.prototype; // Array.prototype[@@unscopables]
  // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables

  if (ArrayPrototype[UNSCOPABLES] == undefined) {
    createNonEnumerableProperty(ArrayPrototype, UNSCOPABLES, objectCreate(null));
  } // add a key to Array.prototype[@@unscopables]


  var addToUnscopables = function (key) {
    ArrayPrototype[UNSCOPABLES][key] = true;
  };

  var iterators = {};
  var correctPrototypeGetter = !fails(function () {
    function F() {
      /* empty */
    }

    F.prototype.constructor = null;
    return Object.getPrototypeOf(new F()) !== F.prototype;
  });
  var IE_PROTO$1 = sharedKey('IE_PROTO');
  var ObjectPrototype$1 = Object.prototype; // `Object.getPrototypeOf` method
  // https://tc39.github.io/ecma262/#sec-object.getprototypeof

  var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
    O = toObject(O);
    if (has(O, IE_PROTO$1)) return O[IE_PROTO$1];

    if (typeof O.constructor == 'function' && O instanceof O.constructor) {
      return O.constructor.prototype;
    }

    return O instanceof Object ? ObjectPrototype$1 : null;
  };
  var ITERATOR = wellKnownSymbol('iterator');
  var BUGGY_SAFARI_ITERATORS = false;

  var returnThis = function () {
    return this;
  }; // `%IteratorPrototype%` object
  // https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object


  var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;

  if ([].keys) {
    arrayIterator = [].keys(); // Safari 8 has buggy iterators w/o `next`

    if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;else {
      PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
      if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;
    }
  }

  if (IteratorPrototype == undefined) IteratorPrototype = {}; // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()

  if (!has(IteratorPrototype, ITERATOR)) {
    createNonEnumerableProperty(IteratorPrototype, ITERATOR, returnThis);
  }

  var iteratorsCore = {
    IteratorPrototype: IteratorPrototype,
    BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
  };
  var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;

  var returnThis$1 = function () {
    return this;
  };

  var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
    var TO_STRING_TAG = NAME + ' Iterator';
    IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, {
      next: createPropertyDescriptor(1, next)
    });
    setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
    iterators[TO_STRING_TAG] = returnThis$1;
    return IteratorConstructor;
  };

  var aPossiblePrototype = function (it) {
    if (!isObject(it) && it !== null) {
      throw TypeError("Can't set " + String(it) + ' as a prototype');
    }

    return it;
  }; // `Object.setPrototypeOf` method
  // https://tc39.github.io/ecma262/#sec-object.setprototypeof
  // Works with __proto__ only. Old v8 can't work with null proto objects.

  /* eslint-disable no-proto */


  var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
    var CORRECT_SETTER = false;
    var test = {};
    var setter;

    try {
      setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
      setter.call(test, []);
      CORRECT_SETTER = test instanceof Array;
    } catch (error) {
      /* empty */
    }

    return function setPrototypeOf(O, proto) {
      anObject(O);
      aPossiblePrototype(proto);
      if (CORRECT_SETTER) setter.call(O, proto);else O.__proto__ = proto;
      return O;
    };
  }() : undefined);
  var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
  var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
  var ITERATOR$1 = wellKnownSymbol('iterator');
  var KEYS = 'keys';
  var VALUES = 'values';
  var ENTRIES = 'entries';

  var returnThis$2 = function () {
    return this;
  };

  var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
    createIteratorConstructor(IteratorConstructor, NAME, next);

    var getIterationMethod = function (KIND) {
      if (KIND === DEFAULT && defaultIterator) return defaultIterator;
      if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];

      switch (KIND) {
        case KEYS:
          return function keys() {
            return new IteratorConstructor(this, KIND);
          };

        case VALUES:
          return function values() {
            return new IteratorConstructor(this, KIND);
          };

        case ENTRIES:
          return function entries() {
            return new IteratorConstructor(this, KIND);
          };
      }

      return function () {
        return new IteratorConstructor(this);
      };
    };

    var TO_STRING_TAG = NAME + ' Iterator';
    var INCORRECT_VALUES_NAME = false;
    var IterablePrototype = Iterable.prototype;
    var nativeIterator = IterablePrototype[ITERATOR$1] || IterablePrototype['@@iterator'] || DEFAULT && IterablePrototype[DEFAULT];
    var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
    var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
    var CurrentIteratorPrototype, methods, KEY; // fix native

    if (anyNativeIterator) {
      CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));

      if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) {
        if (objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) {
          if (objectSetPrototypeOf) {
            objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2);
          } else if (typeof CurrentIteratorPrototype[ITERATOR$1] != 'function') {
            createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$1, returnThis$2);
          }
        } // Set @@toStringTag to native iterators


        setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
      }
    } // fix Array#{values, @@iterator}.name in V8 / FF


    if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
      INCORRECT_VALUES_NAME = true;

      defaultIterator = function values() {
        return nativeIterator.call(this);
      };
    } // define iterator


    if (IterablePrototype[ITERATOR$1] !== defaultIterator) {
      createNonEnumerableProperty(IterablePrototype, ITERATOR$1, defaultIterator);
    }

    iterators[NAME] = defaultIterator; // export additional methods

    if (DEFAULT) {
      methods = {
        values: getIterationMethod(VALUES),
        keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
        entries: getIterationMethod(ENTRIES)
      };
      if (FORCED) for (KEY in methods) {
        if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
          redefine(IterablePrototype, KEY, methods[KEY]);
        }
      } else _export({
        target: NAME,
        proto: true,
        forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME
      }, methods);
    }

    return methods;
  };

  var ARRAY_ITERATOR = 'Array Iterator';
  var setInternalState$1 = internalState.set;
  var getInternalState$1 = internalState.getterFor(ARRAY_ITERATOR); // `Array.prototype.entries` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.entries
  // `Array.prototype.keys` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.keys
  // `Array.prototype.values` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.values
  // `Array.prototype[@@iterator]` method
  // https://tc39.github.io/ecma262/#sec-array.prototype-@@iterator
  // `CreateArrayIterator` internal method
  // https://tc39.github.io/ecma262/#sec-createarrayiterator

  var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
    setInternalState$1(this, {
      type: ARRAY_ITERATOR,
      target: toIndexedObject(iterated),
      // target
      index: 0,
      // next index
      kind: kind // kind

    }); // `%ArrayIteratorPrototype%.next` method
    // https://tc39.github.io/ecma262/#sec-%arrayiteratorprototype%.next
  }, function () {
    var state = getInternalState$1(this);
    var target = state.target;
    var kind = state.kind;
    var index = state.index++;

    if (!target || index >= target.length) {
      state.target = undefined;
      return {
        value: undefined,
        done: true
      };
    }

    if (kind == 'keys') return {
      value: index,
      done: false
    };
    if (kind == 'values') return {
      value: target[index],
      done: false
    };
    return {
      value: [index, target[index]],
      done: false
    };
  }, 'values'); // argumentsList[@@iterator] is %ArrayProto_values%
  // https://tc39.github.io/ecma262/#sec-createunmappedargumentsobject
  // https://tc39.github.io/ecma262/#sec-createmappedargumentsobject

  iterators.Arguments = iterators.Array; // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables

  addToUnscopables('keys');
  addToUnscopables('values');
  addToUnscopables('entries');
  var nativeAssign = Object.assign; // `Object.assign` method
  // https://tc39.github.io/ecma262/#sec-object.assign
  // should work with symbols and should have deterministic property order (V8 bug)

  var objectAssign = !nativeAssign || fails(function () {
    var A = {};
    var B = {}; // eslint-disable-next-line no-undef

    var symbol = Symbol();
    var alphabet = 'abcdefghijklmnopqrst';
    A[symbol] = 7;
    alphabet.split('').forEach(function (chr) {
      B[chr] = chr;
    });
    return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet;
  }) ? function assign(target, source) {
    // eslint-disable-line no-unused-vars
    var T = toObject(target);
    var argumentsLength = arguments.length;
    var index = 1;
    var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
    var propertyIsEnumerable = objectPropertyIsEnumerable.f;

    while (argumentsLength > index) {
      var S = indexedObject(arguments[index++]);
      var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
      var length = keys.length;
      var j = 0;
      var key;

      while (length > j) {
        key = keys[j++];
        if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
      }
    }

    return T;
  } : nativeAssign; // `Object.assign` method
  // https://tc39.github.io/ecma262/#sec-object.assign

  _export({
    target: 'Object',
    stat: true,
    forced: Object.assign !== objectAssign
  }, {
    assign: objectAssign
  });

  var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag'); // ES3 wrong here

  var CORRECT_ARGUMENTS = classofRaw(function () {
    return arguments;
  }()) == 'Arguments'; // fallback for IE11 Script Access Denied error

  var tryGet = function (it, key) {
    try {
      return it[key];
    } catch (error) {
      /* empty */
    }
  }; // getting tag from ES6+ `Object.prototype.toString`


  var classof = function (it) {
    var O, tag, result;
    return it === undefined ? 'Undefined' : it === null ? 'Null' // @@toStringTag case
    : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$1)) == 'string' ? tag // builtinTag case
    : CORRECT_ARGUMENTS ? classofRaw(O) // ES3 arguments fallback
    : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
  };

  var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag');
  var test = {};
  test[TO_STRING_TAG$2] = 'z'; // `Object.prototype.toString` method implementation
  // https://tc39.github.io/ecma262/#sec-object.prototype.tostring

  var objectToString = String(test) !== '[object z]' ? function toString() {
    return '[object ' + classof(this) + ']';
  } : test.toString;
  var ObjectPrototype$2 = Object.prototype; // `Object.prototype.toString` method
  // https://tc39.github.io/ecma262/#sec-object.prototype.tostring

  if (objectToString !== ObjectPrototype$2.toString) {
    redefine(ObjectPrototype$2, 'toString', objectToString, {
      unsafe: true
    });
  }

  var freezing = !fails(function () {
    return Object.isExtensible(Object.preventExtensions({}));
  });
  var internalMetadata = createCommonjsModule(function (module) {
    var defineProperty = objectDefineProperty.f;
    var METADATA = uid('meta');
    var id = 0;

    var isExtensible = Object.isExtensible || function () {
      return true;
    };

    var setMetadata = function (it) {
      defineProperty(it, METADATA, {
        value: {
          objectID: 'O' + ++id,
          // object ID
          weakData: {} // weak collections IDs

        }
      });
    };

    var fastKey = function (it, create) {
      // return a primitive with prefix
      if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;

      if (!has(it, METADATA)) {
        // can't set metadata to uncaught frozen object
        if (!isExtensible(it)) return 'F'; // not necessary to add metadata

        if (!create) return 'E'; // add missing metadata

        setMetadata(it); // return object ID
      }

      return it[METADATA].objectID;
    };

    var getWeakData = function (it, create) {
      if (!has(it, METADATA)) {
        // can't set metadata to uncaught frozen object
        if (!isExtensible(it)) return true; // not necessary to add metadata

        if (!create) return false; // add missing metadata

        setMetadata(it); // return the store of weak collections IDs
      }

      return it[METADATA].weakData;
    }; // add metadata on freeze-family methods calling


    var onFreeze = function (it) {
      if (freezing && meta.REQUIRED && isExtensible(it) && !has(it, METADATA)) setMetadata(it);
      return it;
    };

    var meta = module.exports = {
      REQUIRED: false,
      fastKey: fastKey,
      getWeakData: getWeakData,
      onFreeze: onFreeze
    };
    hiddenKeys[METADATA] = true;
  });
  var ITERATOR$2 = wellKnownSymbol('iterator');
  var ArrayPrototype$1 = Array.prototype; // check on default Array iterator

  var isArrayIteratorMethod = function (it) {
    return it !== undefined && (iterators.Array === it || ArrayPrototype$1[ITERATOR$2] === it);
  };

  var ITERATOR$3 = wellKnownSymbol('iterator');

  var getIteratorMethod = function (it) {
    if (it != undefined) return it[ITERATOR$3] || it['@@iterator'] || iterators[classof(it)];
  }; // call something on iterator step with safe closing on error


  var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
    try {
      return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value); // 7.4.6 IteratorClose(iterator, completion)
    } catch (error) {
      var returnMethod = iterator['return'];
      if (returnMethod !== undefined) anObject(returnMethod.call(iterator));
      throw error;
    }
  };

  var iterate_1 = createCommonjsModule(function (module) {
    var Result = function (stopped, result) {
      this.stopped = stopped;
      this.result = result;
    };

    var iterate = module.exports = function (iterable, fn, that, AS_ENTRIES, IS_ITERATOR) {
      var boundFunction = bindContext(fn, that, AS_ENTRIES ? 2 : 1);
      var iterator, iterFn, index, length, result, next, step;

      if (IS_ITERATOR) {
        iterator = iterable;
      } else {
        iterFn = getIteratorMethod(iterable);
        if (typeof iterFn != 'function') throw TypeError('Target is not iterable'); // optimisation for array iterators

        if (isArrayIteratorMethod(iterFn)) {
          for (index = 0, length = toLength(iterable.length); length > index; index++) {
            result = AS_ENTRIES ? boundFunction(anObject(step = iterable[index])[0], step[1]) : boundFunction(iterable[index]);
            if (result && result instanceof Result) return result;
          }

          return new Result(false);
        }

        iterator = iterFn.call(iterable);
      }

      next = iterator.next;

      while (!(step = next.call(iterator)).done) {
        result = callWithSafeIterationClosing(iterator, boundFunction, step.value, AS_ENTRIES);
        if (typeof result == 'object' && result && result instanceof Result) return result;
      }

      return new Result(false);
    };

    iterate.stop = function (result) {
      return new Result(true, result);
    };
  });

  var anInstance = function (it, Constructor, name) {
    if (!(it instanceof Constructor)) {
      throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
    }

    return it;
  };

  var ITERATOR$4 = wellKnownSymbol('iterator');
  var SAFE_CLOSING = false;

  try {
    var called = 0;
    var iteratorWithReturn = {
      next: function () {
        return {
          done: !!called++
        };
      },
      'return': function () {
        SAFE_CLOSING = true;
      }
    };

    iteratorWithReturn[ITERATOR$4] = function () {
      return this;
    }; // eslint-disable-next-line no-throw-literal


    Array.from(iteratorWithReturn, function () {
      throw 2;
    });
  } catch (error) {
    /* empty */
  }

  var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
    if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
    var ITERATION_SUPPORT = false;

    try {
      var object = {};

      object[ITERATOR$4] = function () {
        return {
          next: function () {
            return {
              done: ITERATION_SUPPORT = true
            };
          }
        };
      };

      exec(object);
    } catch (error) {
      /* empty */
    }

    return ITERATION_SUPPORT;
  }; // makes subclassing work correct for wrapped built-ins


  var inheritIfRequired = function ($this, dummy, Wrapper) {
    var NewTarget, NewTargetPrototype;
    if ( // it can work only with native `setPrototypeOf`
    objectSetPrototypeOf && // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
    typeof (NewTarget = dummy.constructor) == 'function' && NewTarget !== Wrapper && isObject(NewTargetPrototype = NewTarget.prototype) && NewTargetPrototype !== Wrapper.prototype) objectSetPrototypeOf($this, NewTargetPrototype);
    return $this;
  };

  var collection = function (CONSTRUCTOR_NAME, wrapper, common, IS_MAP, IS_WEAK) {
    var NativeConstructor = global_1[CONSTRUCTOR_NAME];
    var NativePrototype = NativeConstructor && NativeConstructor.prototype;
    var Constructor = NativeConstructor;
    var ADDER = IS_MAP ? 'set' : 'add';
    var exported = {};

    var fixMethod = function (KEY) {
      var nativeMethod = NativePrototype[KEY];
      redefine(NativePrototype, KEY, KEY == 'add' ? function add(value) {
        nativeMethod.call(this, value === 0 ? 0 : value);
        return this;
      } : KEY == 'delete' ? function (key) {
        return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
      } : KEY == 'get' ? function get(key) {
        return IS_WEAK && !isObject(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
      } : KEY == 'has' ? function has(key) {
        return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
      } : function set(key, value) {
        nativeMethod.call(this, key === 0 ? 0 : key, value);
        return this;
      });
    }; // eslint-disable-next-line max-len


    if (isForced_1(CONSTRUCTOR_NAME, typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
      new NativeConstructor().entries().next();
    })))) {
      // create collection constructor
      Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
      internalMetadata.REQUIRED = true;
    } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
      var instance = new Constructor(); // early implementations not supports chaining

      var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance; // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false

      var THROWS_ON_PRIMITIVES = fails(function () {
        instance.has(1);
      }); // most early implementations doesn't supports iterables, most modern - not close it correctly
      // eslint-disable-next-line no-new

      var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) {
        new NativeConstructor(iterable);
      }); // for early implementations -0 and +0 not the same

      var BUGGY_ZERO = !IS_WEAK && fails(function () {
        // V8 ~ Chromium 42- fails only with 5+ elements
        var $instance = new NativeConstructor();
        var index = 5;

        while (index--) $instance[ADDER](index, index);

        return !$instance.has(-0);
      });

      if (!ACCEPT_ITERABLES) {
        Constructor = wrapper(function (dummy, iterable) {
          anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
          var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
          if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
          return that;
        });
        Constructor.prototype = NativePrototype;
        NativePrototype.constructor = Constructor;
      }

      if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
        fixMethod('delete');
        fixMethod('has');
        IS_MAP && fixMethod('get');
      }

      if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER); // weak collections should not contains .clear method

      if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
    }

    exported[CONSTRUCTOR_NAME] = Constructor;

    _export({
      global: true,
      forced: Constructor != NativeConstructor
    }, exported);

    setToStringTag(Constructor, CONSTRUCTOR_NAME);
    if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
    return Constructor;
  };

  var redefineAll = function (target, src, options) {
    for (var key in src) redefine(target, key, src[key], options);

    return target;
  };

  var SPECIES$3 = wellKnownSymbol('species');

  var setSpecies = function (CONSTRUCTOR_NAME) {
    var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
    var defineProperty = objectDefineProperty.f;

    if (descriptors && Constructor && !Constructor[SPECIES$3]) {
      defineProperty(Constructor, SPECIES$3, {
        configurable: true,
        get: function () {
          return this;
        }
      });
    }
  };

  var defineProperty$4 = objectDefineProperty.f;
  var fastKey = internalMetadata.fastKey;
  var setInternalState$2 = internalState.set;
  var internalStateGetterFor = internalState.getterFor;
  var collectionStrong = {
    getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
      var C = wrapper(function (that, iterable) {
        anInstance(that, C, CONSTRUCTOR_NAME);
        setInternalState$2(that, {
          type: CONSTRUCTOR_NAME,
          index: objectCreate(null),
          first: undefined,
          last: undefined,
          size: 0
        });
        if (!descriptors) that.size = 0;
        if (iterable != undefined) iterate_1(iterable, that[ADDER], that, IS_MAP);
      });
      var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);

      var define = function (that, key, value) {
        var state = getInternalState(that);
        var entry = getEntry(that, key);
        var previous, index; // change existing entry

        if (entry) {
          entry.value = value; // create new entry
        } else {
          state.last = entry = {
            index: index = fastKey(key, true),
            key: key,
            value: value,
            previous: previous = state.last,
            next: undefined,
            removed: false
          };
          if (!state.first) state.first = entry;
          if (previous) previous.next = entry;
          if (descriptors) state.size++;else that.size++; // add to index

          if (index !== 'F') state.index[index] = entry;
        }

        return that;
      };

      var getEntry = function (that, key) {
        var state = getInternalState(that); // fast case

        var index = fastKey(key);
        var entry;
        if (index !== 'F') return state.index[index]; // frozen object case

        for (entry = state.first; entry; entry = entry.next) {
          if (entry.key == key) return entry;
        }
      };

      redefineAll(C.prototype, {
        // 23.1.3.1 Map.prototype.clear()
        // 23.2.3.2 Set.prototype.clear()
        clear: function clear() {
          var that = this;
          var state = getInternalState(that);
          var data = state.index;
          var entry = state.first;

          while (entry) {
            entry.removed = true;
            if (entry.previous) entry.previous = entry.previous.next = undefined;
            delete data[entry.index];
            entry = entry.next;
          }

          state.first = state.last = undefined;
          if (descriptors) state.size = 0;else that.size = 0;
        },
        // 23.1.3.3 Map.prototype.delete(key)
        // 23.2.3.4 Set.prototype.delete(value)
        'delete': function (key) {
          var that = this;
          var state = getInternalState(that);
          var entry = getEntry(that, key);

          if (entry) {
            var next = entry.next;
            var prev = entry.previous;
            delete state.index[entry.index];
            entry.removed = true;
            if (prev) prev.next = next;
            if (next) next.previous = prev;
            if (state.first == entry) state.first = next;
            if (state.last == entry) state.last = prev;
            if (descriptors) state.size--;else that.size--;
          }

          return !!entry;
        },
        // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
        // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
        forEach: function forEach(callbackfn
        /* , that = undefined */
        ) {
          var state = getInternalState(this);
          var boundFunction = bindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
          var entry;

          while (entry = entry ? entry.next : state.first) {
            boundFunction(entry.value, entry.key, this); // revert to the last existing entry

            while (entry && entry.removed) entry = entry.previous;
          }
        },
        // 23.1.3.7 Map.prototype.has(key)
        // 23.2.3.7 Set.prototype.has(value)
        has: function has(key) {
          return !!getEntry(this, key);
        }
      });
      redefineAll(C.prototype, IS_MAP ? {
        // 23.1.3.6 Map.prototype.get(key)
        get: function get(key) {
          var entry = getEntry(this, key);
          return entry && entry.value;
        },
        // 23.1.3.9 Map.prototype.set(key, value)
        set: function set(key, value) {
          return define(this, key === 0 ? 0 : key, value);
        }
      } : {
        // 23.2.3.1 Set.prototype.add(value)
        add: function add(value) {
          return define(this, value = value === 0 ? 0 : value, value);
        }
      });
      if (descriptors) defineProperty$4(C.prototype, 'size', {
        get: function () {
          return getInternalState(this).size;
        }
      });
      return C;
    },
    setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
      var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
      var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
      var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME); // add .keys, .values, .entries, [@@iterator]
      // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11

      defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
        setInternalState$2(this, {
          type: ITERATOR_NAME,
          target: iterated,
          state: getInternalCollectionState(iterated),
          kind: kind,
          last: undefined
        });
      }, function () {
        var state = getInternalIteratorState(this);
        var kind = state.kind;
        var entry = state.last; // revert to the last existing entry

        while (entry && entry.removed) entry = entry.previous; // get next entry


        if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
          // or finish the iteration
          state.target = undefined;
          return {
            value: undefined,
            done: true
          };
        } // return step by kind


        if (kind == 'keys') return {
          value: entry.key,
          done: false
        };
        if (kind == 'values') return {
          value: entry.value,
          done: false
        };
        return {
          value: [entry.key, entry.value],
          done: false
        };
      }, IS_MAP ? 'entries' : 'values', !IS_MAP, true); // add [@@species], 23.1.2.2, 23.2.2.2

      setSpecies(CONSTRUCTOR_NAME);
    }
  }; // `Set` constructor
  // https://tc39.github.io/ecma262/#sec-set-objects

  collection('Set', function (get) {
    return function Set() {
      return get(this, arguments.length ? arguments[0] : undefined);
    };
  }, collectionStrong); // `String.prototype.{ codePointAt, at }` methods implementation

  var createMethod$2 = function (CONVERT_TO_STRING) {
    return function ($this, pos) {
      var S = String(requireObjectCoercible($this));
      var position = toInteger(pos);
      var size = S.length;
      var first, second;
      if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
      first = S.charCodeAt(position);
      return first < 0xD800 || first > 0xDBFF || position + 1 === size || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF ? CONVERT_TO_STRING ? S.charAt(position) : first : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
    };
  };

  var stringMultibyte = {
    // `String.prototype.codePointAt` method
    // https://tc39.github.io/ecma262/#sec-string.prototype.codepointat
    codeAt: createMethod$2(false),
    // `String.prototype.at` method
    // https://github.com/mathiasbynens/String.prototype.at
    charAt: createMethod$2(true)
  };
  var charAt = stringMultibyte.charAt;
  var STRING_ITERATOR = 'String Iterator';
  var setInternalState$3 = internalState.set;
  var getInternalState$2 = internalState.getterFor(STRING_ITERATOR); // `String.prototype[@@iterator]` method
  // https://tc39.github.io/ecma262/#sec-string.prototype-@@iterator

  defineIterator(String, 'String', function (iterated) {
    setInternalState$3(this, {
      type: STRING_ITERATOR,
      string: String(iterated),
      index: 0
    }); // `%StringIteratorPrototype%.next` method
    // https://tc39.github.io/ecma262/#sec-%stringiteratorprototype%.next
  }, function next() {
    var state = getInternalState$2(this);
    var string = state.string;
    var index = state.index;
    var point;
    if (index >= string.length) return {
      value: undefined,
      done: true
    };
    point = charAt(string, index);
    state.index += point.length;
    return {
      value: point,
      done: false
    };
  }); // iterable DOM collections
  // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods

  var domIterables = {
    CSSRuleList: 0,
    CSSStyleDeclaration: 0,
    CSSValueList: 0,
    ClientRectList: 0,
    DOMRectList: 0,
    DOMStringList: 0,
    DOMTokenList: 1,
    DataTransferItemList: 0,
    FileList: 0,
    HTMLAllCollection: 0,
    HTMLCollection: 0,
    HTMLFormElement: 0,
    HTMLSelectElement: 0,
    MediaList: 0,
    MimeTypeArray: 0,
    NamedNodeMap: 0,
    NodeList: 1,
    PaintRequestList: 0,
    Plugin: 0,
    PluginArray: 0,
    SVGLengthList: 0,
    SVGNumberList: 0,
    SVGPathSegList: 0,
    SVGPointList: 0,
    SVGStringList: 0,
    SVGTransformList: 0,
    SourceBufferList: 0,
    StyleSheetList: 0,
    TextTrackCueList: 0,
    TextTrackList: 0,
    TouchList: 0
  };
  var ITERATOR$5 = wellKnownSymbol('iterator');
  var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
  var ArrayValues = es_array_iterator.values;

  for (var COLLECTION_NAME in domIterables) {
    var Collection = global_1[COLLECTION_NAME];
    var CollectionPrototype = Collection && Collection.prototype;

    if (CollectionPrototype) {
      // some Chrome versions have non-configurable methods on DOMTokenList
      if (CollectionPrototype[ITERATOR$5] !== ArrayValues) try {
        createNonEnumerableProperty(CollectionPrototype, ITERATOR$5, ArrayValues);
      } catch (error) {
        CollectionPrototype[ITERATOR$5] = ArrayValues;
      }

      if (!CollectionPrototype[TO_STRING_TAG$3]) {
        createNonEnumerableProperty(CollectionPrototype, TO_STRING_TAG$3, COLLECTION_NAME);
      }

      if (domIterables[COLLECTION_NAME]) for (var METHOD_NAME in es_array_iterator) {
        // some Chrome versions have non-configurable methods on DOMTokenList
        if (CollectionPrototype[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
          createNonEnumerableProperty(CollectionPrototype, METHOD_NAME, es_array_iterator[METHOD_NAME]);
        } catch (error) {
          CollectionPrototype[METHOD_NAME] = es_array_iterator[METHOD_NAME];
        }
      }
    }
  }

  function _arrayWithoutHoles(arr) {
    if (Array.isArray(arr)) {
      for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) {
        arr2[i] = arr[i];
      }

      return arr2;
    }
  }

  function _iterableToArray(iter) {
    if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
  }

  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance");
  }

  function _toConsumableArray(arr) {
    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
  }

  var methods = {};
  var names = [];

  function registerMethods(name, m) {
    if (Array.isArray(name)) {
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = name[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var _name = _step.value;
          registerMethods(_name, m);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return;
    }

    if (_typeof(name) === 'object') {
      for (var _name2 in name) {
        registerMethods(_name2, name[_name2]);
      }

      return;
    }

    addMethodNames(Object.getOwnPropertyNames(m));
    methods[name] = Object.assign(methods[name] || {}, m);
  }

  function getMethodsFor(name) {
    return methods[name] || {};
  }

  function getMethodNames() {
    return _toConsumableArray(new Set(names));
  }

  function addMethodNames(_names) {
    names.push.apply(names, _toConsumableArray(_names));
  }

  var $includes = arrayIncludes.includes; // `Array.prototype.includes` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.includes

  _export({
    target: 'Array',
    proto: true
  }, {
    includes: function includes(el
    /* , fromIndex = 0 */
    ) {
      return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
    }
  }); // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables


  addToUnscopables('includes'); // `RegExp.prototype.flags` getter implementation
  // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags

  var regexpFlags = function () {
    var that = anObject(this);
    var result = '';
    if (that.global) result += 'g';
    if (that.ignoreCase) result += 'i';
    if (that.multiline) result += 'm';
    if (that.dotAll) result += 's';
    if (that.unicode) result += 'u';
    if (that.sticky) result += 'y';
    return result;
  };

  var nativeExec = RegExp.prototype.exec; // This always refers to the native implementation, because the
  // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
  // which loads this file before patching the method.

  var nativeReplace = String.prototype.replace;
  var patchedExec = nativeExec;

  var UPDATES_LAST_INDEX_WRONG = function () {
    var re1 = /a/;
    var re2 = /b*/g;
    nativeExec.call(re1, 'a');
    nativeExec.call(re2, 'a');
    return re1.lastIndex !== 0 || re2.lastIndex !== 0;
  }(); // nonparticipating capturing group, copied from es5-shim's String#split patch.


  var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
  var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED;

  if (PATCH) {
    patchedExec = function exec(str) {
      var re = this;
      var lastIndex, reCopy, match, i;

      if (NPCG_INCLUDED) {
        reCopy = new RegExp('^' + re.source + '$(?!\\s)', regexpFlags.call(re));
      }

      if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
      match = nativeExec.call(re, str);

      if (UPDATES_LAST_INDEX_WRONG && match) {
        re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
      }

      if (NPCG_INCLUDED && match && match.length > 1) {
        // Fix browsers whose `exec` methods don't consistently return `undefined`
        // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
        nativeReplace.call(match[0], reCopy, function () {
          for (i = 1; i < arguments.length - 2; i++) {
            if (arguments[i] === undefined) match[i] = undefined;
          }
        });
      }

      return match;
    };
  }

  var regexpExec = patchedExec;

  _export({
    target: 'RegExp',
    proto: true,
    forced: /./.exec !== regexpExec
  }, {
    exec: regexpExec
  });

  var MATCH = wellKnownSymbol('match'); // `IsRegExp` abstract operation
  // https://tc39.github.io/ecma262/#sec-isregexp

  var isRegexp = function (it) {
    var isRegExp;
    return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
  };

  var notARegexp = function (it) {
    if (isRegexp(it)) {
      throw TypeError("The method doesn't accept regular expressions");
    }

    return it;
  };

  var MATCH$1 = wellKnownSymbol('match');

  var correctIsRegexpLogic = function (METHOD_NAME) {
    var regexp = /./;

    try {
      '/./'[METHOD_NAME](regexp);
    } catch (e) {
      try {
        regexp[MATCH$1] = false;
        return '/./'[METHOD_NAME](regexp);
      } catch (f) {
        /* empty */
      }
    }

    return false;
  }; // `String.prototype.includes` method
  // https://tc39.github.io/ecma262/#sec-string.prototype.includes


  _export({
    target: 'String',
    proto: true,
    forced: !correctIsRegexpLogic('includes')
  }, {
    includes: function includes(searchString
    /* , position = 0 */
    ) {
      return !!~String(requireObjectCoercible(this)).indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var SPECIES$4 = wellKnownSymbol('species');
  var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
    // #replace needs built-in support for named groups.
    // #match works fine because it just return the exec results, even if it has
    // a "grops" property.
    var re = /./;

    re.exec = function () {
      var result = [];
      result.groups = {
        a: '7'
      };
      return result;
    };

    return ''.replace(re, '$<a>') !== '7';
  }); // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
  // Weex JS has frozen built-in prototypes, so use try / catch wrapper

  var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
    var re = /(?:)/;
    var originalExec = re.exec;

    re.exec = function () {
      return originalExec.apply(this, arguments);
    };

    var result = 'ab'.split(re);
    return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
  });

  var fixRegexpWellKnownSymbolLogic = function (KEY, length, exec, sham) {
    var SYMBOL = wellKnownSymbol(KEY);
    var DELEGATES_TO_SYMBOL = !fails(function () {
      // String methods call symbol-named RegEp methods
      var O = {};

      O[SYMBOL] = function () {
        return 7;
      };

      return ''[KEY](O) != 7;
    });
    var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
      // Symbol-named RegExp methods call .exec
      var execCalled = false;
      var re = /a/;

      if (KEY === 'split') {
        // We can't use real regex here since it causes deoptimization
        // and serious performance degradation in V8
        // https://github.com/zloirock/core-js/issues/306
        re = {}; // RegExp[@@split] doesn't call the regex's exec method, but first creates
        // a new one. We need to return the patched regex when creating the new one.

        re.constructor = {};

        re.constructor[SPECIES$4] = function () {
          return re;
        };

        re.flags = '';
        re[SYMBOL] = /./[SYMBOL];
      }

      re.exec = function () {
        execCalled = true;
        return null;
      };

      re[SYMBOL]('');
      return !execCalled;
    });

    if (!DELEGATES_TO_SYMBOL || !DELEGATES_TO_EXEC || KEY === 'replace' && !REPLACE_SUPPORTS_NAMED_GROUPS || KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC) {
      var nativeRegExpMethod = /./[SYMBOL];
      var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
        if (regexp.exec === regexpExec) {
          if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
            // The native String method already delegates to @@method (this
            // polyfilled function), leasing to infinite recursion.
            // We avoid it by directly calling the native @@method method.
            return {
              done: true,
              value: nativeRegExpMethod.call(regexp, str, arg2)
            };
          }

          return {
            done: true,
            value: nativeMethod.call(str, regexp, arg2)
          };
        }

        return {
          done: false
        };
      });
      var stringMethod = methods[0];
      var regexMethod = methods[1];
      redefine(String.prototype, KEY, stringMethod);
      redefine(RegExp.prototype, SYMBOL, length == 2 // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
      // 21.2.5.11 RegExp.prototype[@@split](string, limit)
      ? function (string, arg) {
        return regexMethod.call(string, this, arg);
      } // 21.2.5.6 RegExp.prototype[@@match](string)
      // 21.2.5.9 RegExp.prototype[@@search](string)
      : function (string) {
        return regexMethod.call(string, this);
      });
      if (sham) createNonEnumerableProperty(RegExp.prototype[SYMBOL], 'sham', true);
    }
  };

  var charAt$1 = stringMultibyte.charAt; // `AdvanceStringIndex` abstract operation
  // https://tc39.github.io/ecma262/#sec-advancestringindex

  var advanceStringIndex = function (S, index, unicode) {
    return index + (unicode ? charAt$1(S, index).length : 1);
  }; // `RegExpExec` abstract operation
  // https://tc39.github.io/ecma262/#sec-regexpexec


  var regexpExecAbstract = function (R, S) {
    var exec = R.exec;

    if (typeof exec === 'function') {
      var result = exec.call(R, S);

      if (typeof result !== 'object') {
        throw TypeError('RegExp exec method returned something other than an Object or null');
      }

      return result;
    }

    if (classofRaw(R) !== 'RegExp') {
      throw TypeError('RegExp#exec called on incompatible receiver');
    }

    return regexpExec.call(R, S);
  };

  var max$2 = Math.max;
  var min$2 = Math.min;
  var floor$1 = Math.floor;
  var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d\d?|<[^>]*>)/g;
  var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d\d?)/g;

  var maybeToString = function (it) {
    return it === undefined ? it : String(it);
  }; // @@replace logic


  fixRegexpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, maybeCallNative) {
    return [// `String.prototype.replace` method
    // https://tc39.github.io/ecma262/#sec-string.prototype.replace
    function replace(searchValue, replaceValue) {
      var O = requireObjectCoercible(this);
      var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
      return replacer !== undefined ? replacer.call(searchValue, O, replaceValue) : nativeReplace.call(String(O), searchValue, replaceValue);
    }, // `RegExp.prototype[@@replace]` method
    // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace
    function (regexp, replaceValue) {
      var res = maybeCallNative(nativeReplace, regexp, this, replaceValue);
      if (res.done) return res.value;
      var rx = anObject(regexp);
      var S = String(this);
      var functionalReplace = typeof replaceValue === 'function';
      if (!functionalReplace) replaceValue = String(replaceValue);
      var global = rx.global;

      if (global) {
        var fullUnicode = rx.unicode;
        rx.lastIndex = 0;
      }

      var results = [];

      while (true) {
        var result = regexpExecAbstract(rx, S);
        if (result === null) break;
        results.push(result);
        if (!global) break;
        var matchStr = String(result[0]);
        if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
      }

      var accumulatedResult = '';
      var nextSourcePosition = 0;

      for (var i = 0; i < results.length; i++) {
        result = results[i];
        var matched = String(result[0]);
        var position = max$2(min$2(toInteger(result.index), S.length), 0);
        var captures = []; // NOTE: This is equivalent to
        //   captures = result.slice(1).map(maybeToString)
        // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
        // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
        // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.

        for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));

        var namedCaptures = result.groups;

        if (functionalReplace) {
          var replacerArgs = [matched].concat(captures, position, S);
          if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
          var replacement = String(replaceValue.apply(undefined, replacerArgs));
        } else {
          replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
        }

        if (position >= nextSourcePosition) {
          accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
          nextSourcePosition = position + matched.length;
        }
      }

      return accumulatedResult + S.slice(nextSourcePosition);
    }]; // https://tc39.github.io/ecma262/#sec-getsubstitution

    function getSubstitution(matched, str, position, captures, namedCaptures, replacement) {
      var tailPos = position + matched.length;
      var m = captures.length;
      var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;

      if (namedCaptures !== undefined) {
        namedCaptures = toObject(namedCaptures);
        symbols = SUBSTITUTION_SYMBOLS;
      }

      return nativeReplace.call(replacement, symbols, function (match, ch) {
        var capture;

        switch (ch.charAt(0)) {
          case '$':
            return '$';

          case '&':
            return matched;

          case '`':
            return str.slice(0, position);

          case "'":
            return str.slice(tailPos);

          case '<':
            capture = namedCaptures[ch.slice(1, -1)];
            break;

          default:
            // \d\d?
            var n = +ch;
            if (n === 0) return match;

            if (n > m) {
              var f = floor$1(n / 10);
              if (f === 0) return match;
              if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
              return match;
            }

            capture = captures[n - 1];
        }

        return capture === undefined ? '' : capture;
      });
    }
  }); // a string of all valid unicode whitespaces
  // eslint-disable-next-line max-len

  var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
  var whitespace = '[' + whitespaces + ']';
  var ltrim = RegExp('^' + whitespace + whitespace + '*');
  var rtrim = RegExp(whitespace + whitespace + '*$'); // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation

  var createMethod$3 = function (TYPE) {
    return function ($this) {
      var string = String(requireObjectCoercible($this));
      if (TYPE & 1) string = string.replace(ltrim, '');
      if (TYPE & 2) string = string.replace(rtrim, '');
      return string;
    };
  };

  var stringTrim = {
    // `String.prototype.{ trimLeft, trimStart }` methods
    // https://tc39.github.io/ecma262/#sec-string.prototype.trimstart
    start: createMethod$3(1),
    // `String.prototype.{ trimRight, trimEnd }` methods
    // https://tc39.github.io/ecma262/#sec-string.prototype.trimend
    end: createMethod$3(2),
    // `String.prototype.trim` method
    // https://tc39.github.io/ecma262/#sec-string.prototype.trim
    trim: createMethod$3(3)
  };
  var non = '\u200B\u0085\u180E'; // check that a method works with the correct list
  // of whitespaces and has a correct name

  var forcedStringTrimMethod = function (METHOD_NAME) {
    return fails(function () {
      return !!whitespaces[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces[METHOD_NAME].name !== METHOD_NAME;
    });
  };

  var $trim = stringTrim.trim; // `String.prototype.trim` method
  // https://tc39.github.io/ecma262/#sec-string.prototype.trim

  _export({
    target: 'String',
    proto: true,
    forced: forcedStringTrimMethod('trim')
  }, {
    trim: function trim() {
      return $trim(this);
    }
  }); // Map function


  function map(array, block) {
    var i;
    var il = array.length;
    var result = [];

    for (i = 0; i < il; i++) {
      result.push(block(array[i]));
    }

    return result;
  } // Filter function


  function filter(array, block) {
    var i;
    var il = array.length;
    var result = [];

    for (i = 0; i < il; i++) {
      if (block(array[i])) {
        result.push(array[i]);
      }
    }

    return result;
  } // Degrees to radians


  function radians(d) {
    return d % 360 * Math.PI / 180;
  } // Radians to degrees


  function degrees(r) {
    return r * 180 / Math.PI % 360;
  } // Convert dash-separated-string to camelCase


  function camelCase(s) {
    return s.toLowerCase().replace(/-(.)/g, function (m, g) {
      return g.toUpperCase();
    });
  } // Convert camel cased string to string seperated


  function unCamelCase(s) {
    return s.replace(/([A-Z])/g, function (m, g) {
      return '-' + g.toLowerCase();
    });
  } // Capitalize first letter of a string


  function capitalize(s) {
    return s.charAt(0).toUpperCase() + s.slice(1);
  } // Calculate proportional width and height values when necessary


  function proportionalSize(element, width, height, box) {
    if (width == null || height == null) {
      box = box || element.bbox();

      if (width == null) {
        width = box.width / box.height * height;
      } else if (height == null) {
        height = box.height / box.width * width;
      }
    }

    return {
      width: width,
      height: height
    };
  }

  function getOrigin(o, element) {
    // Allow origin or around as the names
    var origin = o.origin; // o.around == null ? o.origin : o.around

    var ox, oy; // Allow the user to pass a string to rotate around a given point

    if (typeof origin === 'string' || origin == null) {
      // Get the bounding box of the element with no transformations applied
      var string = (origin || 'center').toLowerCase().trim();

      var _element$bbox = element.bbox(),
          height = _element$bbox.height,
          width = _element$bbox.width,
          x = _element$bbox.x,
          y = _element$bbox.y; // Calculate the transformed x and y coordinates


      var bx = string.includes('left') ? x : string.includes('right') ? x + width : x + width / 2;
      var by = string.includes('top') ? y : string.includes('bottom') ? y + height : y + height / 2; // Set the bounds eg : "bottom-left", "Top right", "middle" etc...

      ox = o.ox != null ? o.ox : bx;
      oy = o.oy != null ? o.oy : by;
    } else {
      ox = origin[0];
      oy = origin[1];
    } // Return the origin as it is if it wasn't a string


    return [ox, oy];
  }

  var utils = {
    __proto__: null,
    map: map,
    filter: filter,
    radians: radians,
    degrees: degrees,
    camelCase: camelCase,
    unCamelCase: unCamelCase,
    capitalize: capitalize,
    proportionalSize: proportionalSize,
    getOrigin: getOrigin
  }; // Default namespaces

  var ns = 'http://www.w3.org/2000/svg';
  var xmlns = 'http://www.w3.org/2000/xmlns/';
  var xlink = 'http://www.w3.org/1999/xlink';
  var svgjs = 'http://svgjs.com/svgjs';
  var namespaces = {
    __proto__: null,
    ns: ns,
    xmlns: xmlns,
    xlink: xlink,
    svgjs: svgjs
  };
  var globals = {
    window: typeof window === 'undefined' ? null : window,
    document: typeof document === 'undefined' ? null : document
  };

  function registerWindow() {
    var win = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
    var doc = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
    globals.window = win;
    globals.document = doc;
  }

  function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
      throw new TypeError("Cannot call a class as a function");
    }
  }

  var Base = function Base() {
    _classCallCheck(this, Base);
  };

  var elements = {};
  var root = '___SYMBOL___ROOT___'; // Method for element creation

  function create(name) {
    // create element
    return globals.document.createElementNS(ns, name);
  }

  function makeInstance(element) {
    if (element instanceof Base) return element;

    if (_typeof(element) === 'object') {
      return adopter(element);
    }

    if (element == null) {
      return new elements[root]();
    }

    if (typeof element === 'string' && element.charAt(0) !== '<') {
      return adopter(globals.document.querySelector(element));
    }

    var node = create('svg');
    node.innerHTML = element; // We can use firstChild here because we know,
    // that the first char is < and thus an element

    element = adopter(node.firstChild);
    return element;
  }

  function nodeOrNew(name, node) {
    return node instanceof globals.window.Node ? node : create(name);
  } // Adopt existing svg elements


  function adopt(node) {
    // check for presence of node
    if (!node) return null; // make sure a node isn't already adopted

    if (node.instance instanceof Base) return node.instance; // initialize variables

    var className = capitalize(node.nodeName || 'Dom'); // Make sure that gradients are adopted correctly

    if (className === 'LinearGradient' || className === 'RadialGradient') {
      className = 'Gradient'; // Fallback to Dom if element is not known
    } else if (!elements[className]) {
      className = 'Dom';
    }

    return new elements[className](node);
  }

  var adopter = adopt;

  function mockAdopt() {
    var mock = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : adopt;
    adopter = mock;
  }

  function register(element) {
    var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : element.name;
    var asRoot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
    elements[name] = element;
    if (asRoot) elements[root] = element;
    addMethodNames(Object.getOwnPropertyNames(element.prototype));
    return element;
  }

  function getClass(name) {
    return elements[name];
  } // Element id sequence


  var did = 1000; // Get next named element id

  function eid(name) {
    return 'Svgjs' + capitalize(name) + did++;
  } // Deep new id assignment


  function assignNewId(node) {
    // do the same for SVG child nodes as well
    for (var i = node.children.length - 1; i >= 0; i--) {
      assignNewId(node.children[i]);
    }

    if (node.id) {
      return adopt(node).id(eid(node.nodeName));
    }

    return adopt(node);
  } // Method for extending objects


  function extend(modules, methods, attrCheck) {
    var key, i;
    modules = Array.isArray(modules) ? modules : [modules];

    for (i = modules.length - 1; i >= 0; i--) {
      for (key in methods) {
        var method = methods[key];

        if (attrCheck) {
          method = wrapWithAttrCheck(methods[key]);
        }

        modules[i].prototype[key] = method;
      }
    }
  } // export function extendWithAttrCheck (...args) {
  //   extend(...args, true)
  // }


  function wrapWithAttrCheck(fn) {
    return function () {
      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }

      var o = args[args.length - 1];

      if (o && o.constructor === Object && !(o instanceof Array)) {
        return fn.apply(this, args.slice(0, -1)).attr(o);
      } else {
        return fn.apply(this, args);
      }
    };
  }

  function invent(config) {
    // Create element initializer
    var initializer = typeof config.create === 'function' ? config.create : function (node) {
      this.constructor(node || create(config.create));
    }; // Inherit prototype

    if (config.inherit) {
      /* eslint new-cap: off */
      initializer.prototype = new config.inherit();
      initializer.prototype.constructor = initializer;
    } // Extend with methods


    if (config.extend) {
      extend(initializer, config.extend);
    } // Attach construct method to parent


    if (config.construct) {
      extend(config.parent || elements.Container, config.construct);
    }

    return initializer;
  }

  function siblings() {
    return this.parent().children();
  } // Get the curent position siblings


  function position() {
    return this.parent().index(this);
  } // Get the next element (will return null if there is none)


  function next() {
    return this.siblings()[this.position() + 1];
  } // Get the next element (will return null if there is none)


  function prev() {
    return this.siblings()[this.position() - 1];
  } // Send given element one step forward


  function forward() {
    var i = this.position() + 1;
    var p = this.parent(); // move node one step forward

    p.removeElement(this).add(this, i); // make sure defs node is always at the top

    if (typeof p.isRoot === 'function' && p.isRoot()) {
      p.node.appendChild(p.defs().node);
    }

    return this;
  } // Send given element one step backward


  function backward() {
    var i = this.position();

    if (i > 0) {
      this.parent().removeElement(this).add(this, i - 1);
    }

    return this;
  } // Send given element all the way to the front


  function front() {
    var p = this.parent(); // Move node forward

    p.node.appendChild(this.node); // Make sure defs node is always at the top

    if (typeof p.isRoot === 'function' && p.isRoot()) {
      p.node.appendChild(p.defs().node);
    }

    return this;
  } // Send given element all the way to the back


  function back() {
    if (this.position() > 0) {
      this.parent().removeElement(this).add(this, 0);
    }

    return this;
  } // Inserts a given element before the targeted element


  function before(element) {
    element = makeInstance(element);
    element.remove();
    var i = this.position();
    this.parent().add(element, i);
    return this;
  } // Inserts a given element after the targeted element


  function after(element) {
    element = makeInstance(element);
    element.remove();
    var i = this.position();
    this.parent().add(element, i + 1);
    return this;
  }

  function insertBefore(element) {
    element = makeInstance(element);
    element.before(this);
    return this;
  }

  function insertAfter(element) {
    element = makeInstance(element);
    element.after(this);
    return this;
  }

  registerMethods('Dom', {
    siblings: siblings,
    position: position,
    next: next,
    prev: prev,
    forward: forward,
    backward: backward,
    front: front,
    back: back,
    before: before,
    after: after,
    insertBefore: insertBefore,
    insertAfter: insertAfter
  });
  var $filter = arrayIteration.filter; // `Array.prototype.filter` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.filter
  // with adding support of @@species

  _export({
    target: 'Array',
    proto: true,
    forced: !arrayMethodHasSpeciesSupport('filter')
  }, {
    filter: function filter(callbackfn
    /* , thisArg */
    ) {
      return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var sloppyArrayMethod = function (METHOD_NAME, argument) {
    var method = [][METHOD_NAME];
    return !method || !fails(function () {
      // eslint-disable-next-line no-useless-call,no-throw-literal
      method.call(null, argument || function () {
        throw 1;
      }, 1);
    });
  };

  var $indexOf = arrayIncludes.indexOf;
  var nativeIndexOf = [].indexOf;
  var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
  var SLOPPY_METHOD = sloppyArrayMethod('indexOf'); // `Array.prototype.indexOf` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.indexof

  _export({
    target: 'Array',
    proto: true,
    forced: NEGATIVE_ZERO || SLOPPY_METHOD
  }, {
    indexOf: function indexOf(searchElement
    /* , fromIndex = 0 */
    ) {
      return NEGATIVE_ZERO // convert -0 to +0
      ? nativeIndexOf.apply(this, arguments) || 0 : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var nativeJoin = [].join;
  var ES3_STRINGS = indexedObject != Object;
  var SLOPPY_METHOD$1 = sloppyArrayMethod('join', ','); // `Array.prototype.join` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.join

  _export({
    target: 'Array',
    proto: true,
    forced: ES3_STRINGS || SLOPPY_METHOD$1
  }, {
    join: function join(separator) {
      return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
    }
  });

  var SPECIES$5 = wellKnownSymbol('species'); // `SpeciesConstructor` abstract operation
  // https://tc39.github.io/ecma262/#sec-speciesconstructor

  var speciesConstructor = function (O, defaultConstructor) {
    var C = anObject(O).constructor;
    var S;
    return C === undefined || (S = anObject(C)[SPECIES$5]) == undefined ? defaultConstructor : aFunction$1(S);
  };

  var arrayPush = [].push;
  var min$3 = Math.min;
  var MAX_UINT32 = 0xFFFFFFFF; // babel-minify transpiles RegExp('x', 'y') -> /x/y and it causes SyntaxError

  var SUPPORTS_Y = !fails(function () {
    return !RegExp(MAX_UINT32, 'y');
  }); // @@split logic

  fixRegexpWellKnownSymbolLogic('split', 2, function (SPLIT, nativeSplit, maybeCallNative) {
    var internalSplit;

    if ('abbc'.split(/(b)*/)[1] == 'c' || 'test'.split(/(?:)/, -1).length != 4 || 'ab'.split(/(?:ab)*/).length != 2 || '.'.split(/(.?)(.?)/).length != 4 || '.'.split(/()()/).length > 1 || ''.split(/.?/).length) {
      // based on es5-shim implementation, need to rework it
      internalSplit = function (separator, limit) {
        var string = String(requireObjectCoercible(this));
        var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
        if (lim === 0) return [];
        if (separator === undefined) return [string]; // If `separator` is not a regex, use native split

        if (!isRegexp(separator)) {
          return nativeSplit.call(string, separator, lim);
        }

        var output = [];
        var flags = (separator.ignoreCase ? 'i' : '') + (separator.multiline ? 'm' : '') + (separator.unicode ? 'u' : '') + (separator.sticky ? 'y' : '');
        var lastLastIndex = 0; // Make `global` and avoid `lastIndex` issues by working with a copy

        var separatorCopy = new RegExp(separator.source, flags + 'g');
        var match, lastIndex, lastLength;

        while (match = regexpExec.call(separatorCopy, string)) {
          lastIndex = separatorCopy.lastIndex;

          if (lastIndex > lastLastIndex) {
            output.push(string.slice(lastLastIndex, match.index));
            if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
            lastLength = match[0].length;
            lastLastIndex = lastIndex;
            if (output.length >= lim) break;
          }

          if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
        }

        if (lastLastIndex === string.length) {
          if (lastLength || !separatorCopy.test('')) output.push('');
        } else output.push(string.slice(lastLastIndex));

        return output.length > lim ? output.slice(0, lim) : output;
      }; // Chakra, V8

    } else if ('0'.split(undefined, 0).length) {
      internalSplit = function (separator, limit) {
        return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
      };
    } else internalSplit = nativeSplit;

    return [// `String.prototype.split` method
    // https://tc39.github.io/ecma262/#sec-string.prototype.split
    function split(separator, limit) {
      var O = requireObjectCoercible(this);
      var splitter = separator == undefined ? undefined : separator[SPLIT];
      return splitter !== undefined ? splitter.call(separator, O, limit) : internalSplit.call(String(O), separator, limit);
    }, // `RegExp.prototype[@@split]` method
    // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@split
    //
    // NOTE: This cannot be properly polyfilled in engines that don't support
    // the 'y' flag.
    function (regexp, limit) {
      var res = maybeCallNative(internalSplit, regexp, this, limit, internalSplit !== nativeSplit);
      if (res.done) return res.value;
      var rx = anObject(regexp);
      var S = String(this);
      var C = speciesConstructor(rx, RegExp);
      var unicodeMatching = rx.unicode;
      var flags = (rx.ignoreCase ? 'i' : '') + (rx.multiline ? 'm' : '') + (rx.unicode ? 'u' : '') + (SUPPORTS_Y ? 'y' : 'g'); // ^(? + rx + ) is needed, in combination with some S slicing, to
      // simulate the 'y' flag.

      var splitter = new C(SUPPORTS_Y ? rx : '^(?:' + rx.source + ')', flags);
      var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
      if (lim === 0) return [];
      if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];
      var p = 0;
      var q = 0;
      var A = [];

      while (q < S.length) {
        splitter.lastIndex = SUPPORTS_Y ? q : 0;
        var z = regexpExecAbstract(splitter, SUPPORTS_Y ? S : S.slice(q));
        var e;

        if (z === null || (e = min$3(toLength(splitter.lastIndex + (SUPPORTS_Y ? 0 : q)), S.length)) === p) {
          q = advanceStringIndex(S, q, unicodeMatching);
        } else {
          A.push(S.slice(p, q));
          if (A.length === lim) return A;

          for (var i = 1; i <= z.length - 1; i++) {
            A.push(z[i]);
            if (A.length === lim) return A;
          }

          q = p = e;
        }
      }

      A.push(S.slice(p));
      return A;
    }];
  }, !SUPPORTS_Y); // Parse unit value

  var numberAndUnit = /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i; // Parse hex value

  var hex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i; // Parse rgb value

  var rgb = /rgb\((\d+),(\d+),(\d+)\)/; // Parse reference id

  var reference = /(#[a-z0-9\-_]+)/i; // splits a transformation chain

  var transforms = /\)\s*,?\s*/; // Whitespace

  var whitespace$1 = /\s/g; // Test hex value

  var isHex = /^#[a-f0-9]{3,6}$/i; // Test rgb value

  var isRgb = /^rgb\(/; // Test css declaration

  var isCss = /[^:]+:[^;]+;?/; // Test for blank string

  var isBlank = /^(\s+)?$/; // Test for numeric string

  var isNumber = /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i; // Test for percent value

  var isPercent = /^-?[\d.]+%$/; // Test for image url

  var isImage = /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i; // split at whitespace and comma

  var delimiter = /[\s,]+/; // The following regex are used to parse the d attribute of a path
  // Matches all hyphens which are not after an exponent

  var hyphen = /([^e])-/gi; // Replaces and tests for all path letters

  var pathLetters = /[MLHVCSQTAZ]/gi; // yes we need this one, too

  var isPathLetter = /[MLHVCSQTAZ]/i; // matches 0.154.23.45

  var numbersWithDots = /((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi; // matches .

  var dots = /\./g;
  var regex = {
    __proto__: null,
    numberAndUnit: numberAndUnit,
    hex: hex,
    rgb: rgb,
    reference: reference,
    transforms: transforms,
    whitespace: whitespace$1,
    isHex: isHex,
    isRgb: isRgb,
    isCss: isCss,
    isBlank: isBlank,
    isNumber: isNumber,
    isPercent: isPercent,
    isImage: isImage,
    delimiter: delimiter,
    hyphen: hyphen,
    pathLetters: pathLetters,
    isPathLetter: isPathLetter,
    numbersWithDots: numbersWithDots,
    dots: dots
  };

  function classes() {
    var attr = this.attr('class');
    return attr == null ? [] : attr.trim().split(delimiter);
  } // Return true if class exists on the node, false otherwise


  function hasClass(name) {
    return this.classes().indexOf(name) !== -1;
  } // Add class to the node


  function addClass(name) {
    if (!this.hasClass(name)) {
      var array = this.classes();
      array.push(name);
      this.attr('class', array.join(' '));
    }

    return this;
  } // Remove class from the node


  function removeClass(name) {
    if (this.hasClass(name)) {
      this.attr('class', this.classes().filter(function (c) {
        return c !== name;
      }).join(' '));
    }

    return this;
  } // Toggle the presence of a class on the node


  function toggleClass(name) {
    return this.hasClass(name) ? this.removeClass(name) : this.addClass(name);
  }

  registerMethods('Dom', {
    classes: classes,
    hasClass: hasClass,
    addClass: addClass,
    removeClass: removeClass,
    toggleClass: toggleClass
  });
  var $forEach$1 = arrayIteration.forEach; // `Array.prototype.forEach` method implementation
  // https://tc39.github.io/ecma262/#sec-array.prototype.foreach

  var arrayForEach = sloppyArrayMethod('forEach') ? function forEach(callbackfn
  /* , thisArg */
  ) {
    return $forEach$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
  } : [].forEach; // `Array.prototype.forEach` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.foreach

  _export({
    target: 'Array',
    proto: true,
    forced: [].forEach != arrayForEach
  }, {
    forEach: arrayForEach
  });

  for (var COLLECTION_NAME$1 in domIterables) {
    var Collection$1 = global_1[COLLECTION_NAME$1];
    var CollectionPrototype$1 = Collection$1 && Collection$1.prototype; // some Chrome versions have non-configurable methods on DOMTokenList

    if (CollectionPrototype$1 && CollectionPrototype$1.forEach !== arrayForEach) try {
      createNonEnumerableProperty(CollectionPrototype$1, 'forEach', arrayForEach);
    } catch (error) {
      CollectionPrototype$1.forEach = arrayForEach;
    }
  }

  function css(style, val) {
    var ret = {};

    if (arguments.length === 0) {
      // get full style as object
      this.node.style.cssText.split(/\s*;\s*/).filter(function (el) {
        return !!el.length;
      }).forEach(function (el) {
        var t = el.split(/\s*:\s*/);
        ret[t[0]] = t[1];
      });
      return ret;
    }

    if (arguments.length < 2) {
      // get style properties in the array
      if (Array.isArray(style)) {
        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
          for (var _iterator = style[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var name = _step.value;
            var cased = camelCase(name);
            ret[cased] = this.node.style[cased];
          }
        } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion && _iterator.return != null) {
              _iterator.return();
            }
          } finally {
            if (_didIteratorError) {
              throw _iteratorError;
            }
          }
        }

        return ret;
      } // get style for property


      if (typeof style === 'string') {
        return this.node.style[camelCase(style)];
      } // set styles in object


      if (_typeof(style) === 'object') {
        for (var _name in style) {
          // set empty string if null/undefined/'' was given
          this.node.style[camelCase(_name)] = style[_name] == null || isBlank.test(style[_name]) ? '' : style[_name];
        }
      }
    } // set style for property


    if (arguments.length === 2) {
      this.node.style[camelCase(style)] = val == null || isBlank.test(val) ? '' : val;
    }

    return this;
  } // Show element


  function show() {
    return this.css('display', '');
  } // Hide element


  function hide() {
    return this.css('display', 'none');
  } // Is element visible?


  function visible() {
    return this.css('display') !== 'none';
  }

  registerMethods('Dom', {
    css: css,
    show: show,
    hide: hide,
    visible: visible
  });

  function data$1(a, v, r) {
    if (_typeof(a) === 'object') {
      for (v in a) {
        this.data(v, a[v]);
      }
    } else if (arguments.length < 2) {
      try {
        return JSON.parse(this.attr('data-' + a));
      } catch (e) {
        return this.attr('data-' + a);
      }
    } else {
      this.attr('data-' + a, v === null ? null : r === true || typeof v === 'string' || typeof v === 'number' ? v : JSON.stringify(v));
    }

    return this;
  }

  registerMethods('Dom', {
    data: data$1
  });

  function remember(k, v) {
    // remember every item in an object individually
    if (_typeof(arguments[0]) === 'object') {
      for (var key in k) {
        this.remember(key, k[key]);
      }
    } else if (arguments.length === 1) {
      // retrieve memory
      return this.memory()[k];
    } else {
      // store memory
      this.memory()[k] = v;
    }

    return this;
  } // Erase a given memory


  function forget() {
    if (arguments.length === 0) {
      this._memory = {};
    } else {
      for (var i = arguments.length - 1; i >= 0; i--) {
        delete this.memory()[arguments[i]];
      }
    }

    return this;
  } // This triggers creation of a new hidden class which is not performant
  // However, this function is not rarely used so it will not happen frequently
  // Return local memory object


  function memory() {
    return this._memory = this._memory || {};
  }

  registerMethods('Dom', {
    remember: remember,
    forget: forget,
    memory: memory
  }); // `Array.prototype.{ reduce, reduceRight }` methods implementation

  var createMethod$4 = function (IS_RIGHT) {
    return function (that, callbackfn, argumentsLength, memo) {
      aFunction$1(callbackfn);
      var O = toObject(that);
      var self = indexedObject(O);
      var length = toLength(O.length);
      var index = IS_RIGHT ? length - 1 : 0;
      var i = IS_RIGHT ? -1 : 1;
      if (argumentsLength < 2) while (true) {
        if (index in self) {
          memo = self[index];
          index += i;
          break;
        }

        index += i;

        if (IS_RIGHT ? index < 0 : length <= index) {
          throw TypeError('Reduce of empty array with no initial value');
        }
      }

      for (; IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
        memo = callbackfn(memo, self[index], index, O);
      }

      return memo;
    };
  };

  var arrayReduce = {
    // `Array.prototype.reduce` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.reduce
    left: createMethod$4(false),
    // `Array.prototype.reduceRight` method
    // https://tc39.github.io/ecma262/#sec-array.prototype.reduceright
    right: createMethod$4(true)
  };
  var $reduce = arrayReduce.left; // `Array.prototype.reduce` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.reduce

  _export({
    target: 'Array',
    proto: true,
    forced: sloppyArrayMethod('reduce')
  }, {
    reduce: function reduce(callbackfn
    /* , initialValue */
    ) {
      return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var listenerId = 0;
  var windowEvents = {};

  function getEvents(instance) {
    var n = instance.getEventHolder(); // We dont want to save events in global space

    if (n === globals.window) n = windowEvents;
    if (!n.events) n.events = {};
    return n.events;
  }

  function getEventTarget(instance) {
    return instance.getEventTarget();
  }

  function clearEvents(instance) {
    var n = instance.getEventHolder();
    if (n.events) n.events = {};
  } // Add event binder in the SVG namespace


  function on(node, events, listener, binding, options) {
    var l = listener.bind(binding || node);
    var instance = makeInstance(node);
    var bag = getEvents(instance);
    var n = getEventTarget(instance); // events can be an array of events or a string of events

    events = Array.isArray(events) ? events : events.split(delimiter); // add id to listener

    if (!listener._svgjsListenerId) {
      listener._svgjsListenerId = ++listenerId;
    }

    events.forEach(function (event) {
      var ev = event.split('.')[0];
      var ns = event.split('.')[1] || '*'; // ensure valid object

      bag[ev] = bag[ev] || {};
      bag[ev][ns] = bag[ev][ns] || {}; // reference listener

      bag[ev][ns][listener._svgjsListenerId] = l; // add listener

      n.addEventListener(ev, l, options || false);
    });
  } // Add event unbinder in the SVG namespace


  function off(node, events, listener, options) {
    var instance = makeInstance(node);
    var bag = getEvents(instance);
    var n = getEventTarget(instance); // listener can be a function or a number

    if (typeof listener === 'function') {
      listener = listener._svgjsListenerId;
      if (!listener) return;
    } // events can be an array of events or a string or undefined


    events = Array.isArray(events) ? events : (events || '').split(delimiter);
    events.forEach(function (event) {
      var ev = event && event.split('.')[0];
      var ns = event && event.split('.')[1];
      var namespace, l;

      if (listener) {
        // remove listener reference
        if (bag[ev] && bag[ev][ns || '*']) {
          // removeListener
          n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false);
          delete bag[ev][ns || '*'][listener];
        }
      } else if (ev && ns) {
        // remove all listeners for a namespaced event
        if (bag[ev] && bag[ev][ns]) {
          for (l in bag[ev][ns]) {
            off(n, [ev, ns].join('.'), l);
          }

          delete bag[ev][ns];
        }
      } else if (ns) {
        // remove all listeners for a specific namespace
        for (event in bag) {
          for (namespace in bag[event]) {
            if (ns === namespace) {
              off(n, [event, ns].join('.'));
            }
          }
        }
      } else if (ev) {
        // remove all listeners for the event
        if (bag[ev]) {
          for (namespace in bag[ev]) {
            off(n, [ev, namespace].join('.'));
          }

          delete bag[ev];
        }
      } else {
        // remove all listeners on a given node
        for (event in bag) {
          off(n, event);
        }

        clearEvents(instance);
      }
    });
  }

  function dispatch(node, event, data) {
    var n = getEventTarget(node); // Dispatch event

    if (event instanceof globals.window.Event) {
      n.dispatchEvent(event);
    } else {
      event = new globals.window.CustomEvent(event, {
        detail: data,
        cancelable: true
      });
      n.dispatchEvent(event);
    }

    return event;
  }

  var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
  var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
  var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded'; // We can't use this feature detection in V8 since it causes
  // deoptimization and serious performance degradation
  // https://github.com/zloirock/core-js/issues/679

  var IS_CONCAT_SPREADABLE_SUPPORT = v8Version >= 51 || !fails(function () {
    var array = [];
    array[IS_CONCAT_SPREADABLE] = false;
    return array.concat()[0] !== array;
  });
  var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');

  var isConcatSpreadable = function (O) {
    if (!isObject(O)) return false;
    var spreadable = O[IS_CONCAT_SPREADABLE];
    return spreadable !== undefined ? !!spreadable : isArray(O);
  };

  var FORCED = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT; // `Array.prototype.concat` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.concat
  // with adding support of @@isConcatSpreadable and @@species

  _export({
    target: 'Array',
    proto: true,
    forced: FORCED
  }, {
    concat: function concat(arg) {
      // eslint-disable-line no-unused-vars
      var O = toObject(this);
      var A = arraySpeciesCreate(O, 0);
      var n = 0;
      var i, k, length, len, E;

      for (i = -1, length = arguments.length; i < length; i++) {
        E = i === -1 ? O : arguments[i];

        if (isConcatSpreadable(E)) {
          len = toLength(E.length);
          if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);

          for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
        } else {
          if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
          createProperty(A, n++, E);
        }
      }

      A.length = n;
      return A;
    }
  });

  var $map = arrayIteration.map; // `Array.prototype.map` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.map
  // with adding support of @@species

  _export({
    target: 'Array',
    proto: true,
    forced: !arrayMethodHasSpeciesSupport('map')
  }, {
    map: function map(callbackfn
    /* , thisArg */
    ) {
      return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var DatePrototype = Date.prototype;
  var INVALID_DATE = 'Invalid Date';
  var TO_STRING = 'toString';
  var nativeDateToString = DatePrototype[TO_STRING];
  var getTime = DatePrototype.getTime; // `Date.prototype.toString` method
  // https://tc39.github.io/ecma262/#sec-date.prototype.tostring

  if (new Date(NaN) + '' != INVALID_DATE) {
    redefine(DatePrototype, TO_STRING, function toString() {
      var value = getTime.call(this); // eslint-disable-next-line no-self-compare

      return value === value ? nativeDateToString.call(this) : INVALID_DATE;
    });
  }

  var trim = stringTrim.trim;
  var nativeParseInt = global_1.parseInt;
  var hex$1 = /^[+-]?0[Xx]/;
  var FORCED$1 = nativeParseInt(whitespaces + '08') !== 8 || nativeParseInt(whitespaces + '0x16') !== 22; // `parseInt` method
  // https://tc39.github.io/ecma262/#sec-parseint-string-radix

  var _parseInt = FORCED$1 ? function parseInt(string, radix) {
    var S = trim(String(string));
    return nativeParseInt(S, radix >>> 0 || (hex$1.test(S) ? 16 : 10));
  } : nativeParseInt; // `parseInt` method
  // https://tc39.github.io/ecma262/#sec-parseint-string-radix


  _export({
    global: true,
    forced: parseInt != _parseInt
  }, {
    parseInt: _parseInt
  });

  var TO_STRING$1 = 'toString';
  var RegExpPrototype = RegExp.prototype;
  var nativeToString = RegExpPrototype[TO_STRING$1];
  var NOT_GENERIC = fails(function () {
    return nativeToString.call({
      source: 'a',
      flags: 'b'
    }) != '/a/b';
  }); // FF44- RegExp#toString has a wrong name

  var INCORRECT_NAME = nativeToString.name != TO_STRING$1; // `RegExp.prototype.toString` method
  // https://tc39.github.io/ecma262/#sec-regexp.prototype.tostring

  if (NOT_GENERIC || INCORRECT_NAME) {
    redefine(RegExp.prototype, TO_STRING$1, function toString() {
      var R = anObject(this);
      var p = String(R.source);
      var rf = R.flags;
      var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? regexpFlags.call(R) : rf);
      return '/' + p + '/' + f;
    }, {
      unsafe: true
    });
  }

  function _arrayWithHoles(arr) {
    if (Array.isArray(arr)) return arr;
  }

  function _iterableToArrayLimit(arr, i) {
    if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) {
      return;
    }

    var _arr = [];
    var _n = true;
    var _d = false;
    var _e = undefined;

    try {
      for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
        _arr.push(_s.value);

        if (i && _arr.length === i) break;
      }
    } catch (err) {
      _d = true;
      _e = err;
    } finally {
      try {
        if (!_n && _i["return"] != null) _i["return"]();
      } finally {
        if (_d) throw _e;
      }
    }

    return _arr;
  }

  function _nonIterableRest() {
    throw new TypeError("Invalid attempt to destructure non-iterable instance");
  }

  function _slicedToArray(arr, i) {
    return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
  }

  function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
  }

  function sixDigitHex(hex) {
    return hex.length === 4 ? ['#', hex.substring(1, 2), hex.substring(1, 2), hex.substring(2, 3), hex.substring(2, 3), hex.substring(3, 4), hex.substring(3, 4)].join('') : hex;
  }

  function componentHex(component) {
    var integer = Math.round(component);
    var bounded = Math.max(0, Math.min(255, integer));
    var hex = bounded.toString(16);
    return hex.length === 1 ? '0' + hex : hex;
  }

  function is(object, space) {
    for (var i = space.length; i--;) {
      if (object[space[i]] == null) {
        return false;
      }
    }

    return true;
  }

  function getParameters(a, b) {
    var params = is(a, 'rgb') ? {
      _a: a.r,
      _b: a.g,
      _c: a.b,
      space: 'rgb'
    } : is(a, 'xyz') ? {
      _a: a.x,
      _b: a.y,
      _c: a.z,
      _d: 0,
      space: 'xyz'
    } : is(a, 'hsl') ? {
      _a: a.h,
      _b: a.s,
      _c: a.l,
      _d: 0,
      space: 'hsl'
    } : is(a, 'lab') ? {
      _a: a.l,
      _b: a.a,
      _c: a.b,
      _d: 0,
      space: 'lab'
    } : is(a, 'lch') ? {
      _a: a.l,
      _b: a.c,
      _c: a.h,
      _d: 0,
      space: 'lch'
    } : is(a, 'cmyk') ? {
      _a: a.c,
      _b: a.m,
      _c: a.y,
      _d: a.k,
      space: 'cmyk'
    } : {
      _a: 0,
      _b: 0,
      _c: 0,
      space: 'rgb'
    };
    params.space = b || params.space;
    return params;
  }

  function cieSpace(space) {
    if (space === 'lab' || space === 'xyz' || space === 'lch') {
      return true;
    } else {
      return false;
    }
  }

  function hueToRgb(p, q, t) {
    if (t < 0) t += 1;
    if (t > 1) t -= 1;
    if (t < 1 / 6) return p + (q - p) * 6 * t;
    if (t < 1 / 2) return q;
    if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
    return p;
  }

  var Color = /*#__PURE__*/function () {
    function Color() {
      _classCallCheck(this, Color);

      this.init.apply(this, arguments);
    }

    _createClass(Color, [{
      key: "init",
      value: function init() {
        var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        var b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
        var c = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
        var d = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
        var space = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'rgb'; // This catches the case when a falsy value is passed like ''

        a = !a ? 0 : a; // Reset all values in case the init function is rerun with new color space

        if (this.space) {
          for (var component in this.space) {
            delete this[this.space[component]];
          }
        }

        if (typeof a === 'number') {
          // Allow for the case that we don't need d...
          space = typeof d === 'string' ? d : space;
          d = typeof d === 'string' ? 0 : d; // Assign the values straight to the color

          Object.assign(this, {
            _a: a,
            _b: b,
            _c: c,
            _d: d,
            space: space
          }); // If the user gave us an array, make the color from it
        } else if (a instanceof Array) {
          this.space = b || (typeof a[3] === 'string' ? a[3] : a[4]) || 'rgb';
          Object.assign(this, {
            _a: a[0],
            _b: a[1],
            _c: a[2],
            _d: a[3] || 0
          });
        } else if (a instanceof Object) {
          // Set the object up and assign its values directly
          var values = getParameters(a, b);
          Object.assign(this, values);
        } else if (typeof a === 'string') {
          if (isRgb.test(a)) {
            var noWhitespace = a.replace(whitespace$1, '');

            var _rgb$exec$slice$map = rgb.exec(noWhitespace).slice(1, 4).map(function (v) {
              return parseInt(v);
            }),
                _rgb$exec$slice$map2 = _slicedToArray(_rgb$exec$slice$map, 3),
                _a2 = _rgb$exec$slice$map2[0],
                _b2 = _rgb$exec$slice$map2[1],
                _c2 = _rgb$exec$slice$map2[2];

            Object.assign(this, {
              _a: _a2,
              _b: _b2,
              _c: _c2,
              _d: 0,
              space: 'rgb'
            });
          } else if (isHex.test(a)) {
            var hexParse = function hexParse(v) {
              return parseInt(v, 16);
            };

            var _hex$exec$map = hex.exec(sixDigitHex(a)).map(hexParse),
                _hex$exec$map2 = _slicedToArray(_hex$exec$map, 4),
                _a3 = _hex$exec$map2[1],
                _b3 = _hex$exec$map2[2],
                _c3 = _hex$exec$map2[3];

            Object.assign(this, {
              _a: _a3,
              _b: _b3,
              _c: _c3,
              _d: 0,
              space: 'rgb'
            });
          } else throw Error('Unsupported string format, can\'t construct Color');
        } // Now add the components as a convenience


        var _a = this._a,
            _b = this._b,
            _c = this._c,
            _d = this._d;
        var components = this.space === 'rgb' ? {
          r: _a,
          g: _b,
          b: _c
        } : this.space === 'xyz' ? {
          x: _a,
          y: _b,
          z: _c
        } : this.space === 'hsl' ? {
          h: _a,
          s: _b,
          l: _c
        } : this.space === 'lab' ? {
          l: _a,
          a: _b,
          b: _c
        } : this.space === 'lch' ? {
          l: _a,
          c: _b,
          h: _c
        } : this.space === 'cmyk' ? {
          c: _a,
          m: _b,
          y: _c,
          k: _d
        } : {};
        Object.assign(this, components);
      }
      /*
      Conversion Methods
      */

    }, {
      key: "rgb",
      value: function rgb() {
        if (this.space === 'rgb') {
          return this;
        } else if (cieSpace(this.space)) {
          // Convert to the xyz color space
          var x = this.x,
              y = this.y,
              z = this.z;

          if (this.space === 'lab' || this.space === 'lch') {
            // Get the values in the lab space
            var l = this.l,
                a = this.a,
                _b4 = this.b;

            if (this.space === 'lch') {
              var c = this.c,
                  h = this.h;
              var dToR = Math.PI / 180;
              a = c * Math.cos(dToR * h);
              _b4 = c * Math.sin(dToR * h);
            } // Undo the nonlinear function


            var yL = (l + 16) / 116;
            var xL = a / 500 + yL;
            var zL = yL - _b4 / 200; // Get the xyz values

            var ct = 16 / 116;
            var mx = 0.008856;
            var nm = 7.787;
            x = 0.95047 * (Math.pow(xL, 3) > mx ? Math.pow(xL, 3) : (xL - ct) / nm);
            y = 1.00000 * (Math.pow(yL, 3) > mx ? Math.pow(yL, 3) : (yL - ct) / nm);
            z = 1.08883 * (Math.pow(zL, 3) > mx ? Math.pow(zL, 3) : (zL - ct) / nm);
          } // Convert xyz to unbounded rgb values


          var rU = x * 3.2406 + y * -1.5372 + z * -0.4986;
          var gU = x * -0.9689 + y * 1.8758 + z * 0.0415;
          var bU = x * 0.0557 + y * -0.2040 + z * 1.0570; // Convert the values to true rgb values

          var pow = Math.pow;
          var bd = 0.0031308;
          var r = rU > bd ? 1.055 * pow(rU, 1 / 2.4) - 0.055 : 12.92 * rU;
          var g = gU > bd ? 1.055 * pow(gU, 1 / 2.4) - 0.055 : 12.92 * gU;
          var b = bU > bd ? 1.055 * pow(bU, 1 / 2.4) - 0.055 : 12.92 * bU; // Make and return the color

          var color = new Color(255 * r, 255 * g, 255 * b);
          return color;
        } else if (this.space === 'hsl') {
          // https://bgrins.github.io/TinyColor/docs/tinycolor.html
          // Get the current hsl values
          var _h = this.h,
              s = this.s,
              _l = this.l;
          _h /= 360;
          s /= 100;
          _l /= 100; // If we are grey, then just make the color directly

          if (s === 0) {
            _l *= 255;

            var _color2 = new Color(_l, _l, _l);

            return _color2;
          } // TODO I have no idea what this does :D If you figure it out, tell me!


          var q = _l < 0.5 ? _l * (1 + s) : _l + s - _l * s;
          var p = 2 * _l - q; // Get the rgb values

          var _r = 255 * hueToRgb(p, q, _h + 1 / 3);

          var _g = 255 * hueToRgb(p, q, _h);

          var _b5 = 255 * hueToRgb(p, q, _h - 1 / 3); // Make a new color


          var _color = new Color(_r, _g, _b5);

          return _color;
        } else if (this.space === 'cmyk') {
          // https://gist.github.com/felipesabino/5066336
          // Get the normalised cmyk values
          var _c4 = this.c,
              m = this.m,
              _y = this.y,
              k = this.k; // Get the rgb values

          var _r2 = 255 * (1 - Math.min(1, _c4 * (1 - k) + k));

          var _g2 = 255 * (1 - Math.min(1, m * (1 - k) + k));

          var _b6 = 255 * (1 - Math.min(1, _y * (1 - k) + k)); // Form the color and return it


          var _color3 = new Color(_r2, _g2, _b6);

          return _color3;
        } else {
          return this;
        }
      }
    }, {
      key: "lab",
      value: function lab() {
        // Get the xyz color
        var _this$xyz = this.xyz(),
            x = _this$xyz.x,
            y = _this$xyz.y,
            z = _this$xyz.z; // Get the lab components


        var l = 116 * y - 16;
        var a = 500 * (x - y);
        var b = 200 * (y - z); // Construct and return a new color

        var color = new Color(l, a, b, 'lab');
        return color;
      }
    }, {
      key: "xyz",
      value: function xyz() {
        // Normalise the red, green and blue values
        var _this$rgb = this.rgb(),
            r255 = _this$rgb._a,
            g255 = _this$rgb._b,
            b255 = _this$rgb._c;

        var _map = [r255, g255, b255].map(function (v) {
          return v / 255;
        }),
            _map2 = _slicedToArray(_map, 3),
            r = _map2[0],
            g = _map2[1],
            b = _map2[2]; // Convert to the lab rgb space


        var rL = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
        var gL = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
        var bL = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92; // Convert to the xyz color space without bounding the values

        var xU = (rL * 0.4124 + gL * 0.3576 + bL * 0.1805) / 0.95047;
        var yU = (rL * 0.2126 + gL * 0.7152 + bL * 0.0722) / 1.00000;
        var zU = (rL * 0.0193 + gL * 0.1192 + bL * 0.9505) / 1.08883; // Get the proper xyz values by applying the bounding

        var x = xU > 0.008856 ? Math.pow(xU, 1 / 3) : 7.787 * xU + 16 / 116;
        var y = yU > 0.008856 ? Math.pow(yU, 1 / 3) : 7.787 * yU + 16 / 116;
        var z = zU > 0.008856 ? Math.pow(zU, 1 / 3) : 7.787 * zU + 16 / 116; // Make and return the color

        var color = new Color(x, y, z, 'xyz');
        return color;
      }
    }, {
      key: "lch",
      value: function lch() {
        // Get the lab color directly
        var _this$lab = this.lab(),
            l = _this$lab.l,
            a = _this$lab.a,
            b = _this$lab.b; // Get the chromaticity and the hue using polar coordinates


        var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
        var h = 180 * Math.atan2(b, a) / Math.PI;

        if (h < 0) {
          h *= -1;
          h = 360 - h;
        } // Make a new color and return it


        var color = new Color(l, c, h, 'lch');
        return color;
      }
    }, {
      key: "hsl",
      value: function hsl() {
        // Get the rgb values
        var _this$rgb2 = this.rgb(),
            _a = _this$rgb2._a,
            _b = _this$rgb2._b,
            _c = _this$rgb2._c;

        var _map3 = [_a, _b, _c].map(function (v) {
          return v / 255;
        }),
            _map4 = _slicedToArray(_map3, 3),
            r = _map4[0],
            g = _map4[1],
            b = _map4[2]; // Find the maximum and minimum values to get the lightness


        var max = Math.max(r, g, b);
        var min = Math.min(r, g, b);
        var l = (max + min) / 2; // If the r, g, v values are identical then we are grey

        var isGrey = max === min; // Calculate the hue and saturation

        var delta = max - min;
        var s = isGrey ? 0 : l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
        var h = isGrey ? 0 : max === r ? ((g - b) / delta + (g < b ? 6 : 0)) / 6 : max === g ? ((b - r) / delta + 2) / 6 : max === b ? ((r - g) / delta + 4) / 6 : 0; // Construct and return the new color

        var color = new Color(360 * h, 100 * s, 100 * l, 'hsl');
        return color;
      }
    }, {
      key: "cmyk",
      value: function cmyk() {
        // Get the rgb values for the current color
        var _this$rgb3 = this.rgb(),
            _a = _this$rgb3._a,
            _b = _this$rgb3._b,
            _c = _this$rgb3._c;

        var _map5 = [_a, _b, _c].map(function (v) {
          return v / 255;
        }),
            _map6 = _slicedToArray(_map5, 3),
            r = _map6[0],
            g = _map6[1],
            b = _map6[2]; // Get the cmyk values in an unbounded format


        var k = Math.min(1 - r, 1 - g, 1 - b);

        if (k === 1) {
          // Catch the black case
          return new Color(0, 0, 0, 1, 'cmyk');
        }

        var c = (1 - r - k) / (1 - k);
        var m = (1 - g - k) / (1 - k);
        var y = (1 - b - k) / (1 - k); // Construct the new color

        var color = new Color(c, m, y, k, 'cmyk');
        return color;
      }
      /*
      Input and Output methods
      */

    }, {
      key: "_clamped",
      value: function _clamped() {
        var _this$rgb4 = this.rgb(),
            _a = _this$rgb4._a,
            _b = _this$rgb4._b,
            _c = _this$rgb4._c;

        var max = Math.max,
            min = Math.min,
            round = Math.round;

        var format = function format(v) {
          return max(0, min(round(v), 255));
        };

        return [_a, _b, _c].map(format);
      }
    }, {
      key: "toHex",
      value: function toHex() {
        var _this$_clamped$map = this._clamped().map(componentHex),
            _this$_clamped$map2 = _slicedToArray(_this$_clamped$map, 3),
            r = _this$_clamped$map2[0],
            g = _this$_clamped$map2[1],
            b = _this$_clamped$map2[2];

        return "#".concat(r).concat(g).concat(b);
      }
    }, {
      key: "toString",
      value: function toString() {
        return this.toHex();
      }
    }, {
      key: "toRgb",
      value: function toRgb() {
        var _this$_clamped = this._clamped(),
            _this$_clamped2 = _slicedToArray(_this$_clamped, 3),
            rV = _this$_clamped2[0],
            gV = _this$_clamped2[1],
            bV = _this$_clamped2[2];

        var string = "rgb(".concat(rV, ",").concat(gV, ",").concat(bV, ")");
        return string;
      }
    }, {
      key: "toArray",
      value: function toArray() {
        var _a = this._a,
            _b = this._b,
            _c = this._c,
            _d = this._d,
            space = this.space;
        return [_a, _b, _c, _d, space];
      }
      /*
      Generating random colors
      */

    }], [{
      key: "random",
      value: function random() {
        var mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'vibrant';
        var t = arguments.length > 1 ? arguments[1] : undefined; // Get the math modules

        var random = Math.random,
            round = Math.round,
            sin = Math.sin,
            pi = Math.PI; // Run the correct generator

        if (mode === 'vibrant') {
          var l = (81 - 57) * random() + 57;
          var c = (83 - 45) * random() + 45;
          var h = 360 * random();
          var color = new Color(l, c, h, 'lch');
          return color;
        } else if (mode === 'sine') {
          t = t == null ? random() : t;
          var r = round(80 * sin(2 * pi * t / 0.5 + 0.01) + 150);
          var g = round(50 * sin(2 * pi * t / 0.5 + 4.6) + 200);
          var b = round(100 * sin(2 * pi * t / 0.5 + 2.3) + 150);

          var _color4 = new Color(r, g, b);

          return _color4;
        } else if (mode === 'pastel') {
          var _l2 = (94 - 86) * random() + 86;

          var _c5 = (26 - 9) * random() + 9;

          var _h2 = 360 * random();

          var _color5 = new Color(_l2, _c5, _h2, 'lch');

          return _color5;
        } else if (mode === 'dark') {
          var _l3 = 10 + 10 * random();

          var _c6 = (125 - 75) * random() + 86;

          var _h3 = 360 * random();

          var _color6 = new Color(_l3, _c6, _h3, 'lch');

          return _color6;
        } else if (mode === 'rgb') {
          var _r3 = 255 * random();

          var _g3 = 255 * random();

          var _b7 = 255 * random();

          var _color7 = new Color(_r3, _g3, _b7);

          return _color7;
        } else if (mode === 'lab') {
          var _l4 = 100 * random();

          var a = 256 * random() - 128;

          var _b8 = 256 * random() - 128;

          var _color8 = new Color(_l4, a, _b8, 'lab');

          return _color8;
        } else if (mode === 'grey') {
          var grey = 255 * random();

          var _color9 = new Color(grey, grey, grey);

          return _color9;
        }
      }
      /*
      Constructing colors
      */
      // Test if given value is a color string

    }, {
      key: "test",
      value: function test(color) {
        return typeof color === 'string' && (isHex.test(color) || isRgb.test(color));
      } // Test if given value is an rgb object

    }, {
      key: "isRgb",
      value: function isRgb(color) {
        return color && typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number';
      } // Test if given value is a color

    }, {
      key: "isColor",
      value: function isColor(color) {
        return color && (color instanceof Color || this.isRgb(color) || this.test(color));
      }
    }]);

    return Color;
  }();

  var FAILS_ON_PRIMITIVES$1 = fails(function () {
    objectKeys(1);
  }); // `Object.keys` method
  // https://tc39.github.io/ecma262/#sec-object.keys

  _export({
    target: 'Object',
    stat: true,
    forced: FAILS_ON_PRIMITIVES$1
  }, {
    keys: function keys(it) {
      return objectKeys(toObject(it));
    }
  }); // @@match logic


  fixRegexpWellKnownSymbolLogic('match', 1, function (MATCH, nativeMatch, maybeCallNative) {
    return [// `String.prototype.match` method
    // https://tc39.github.io/ecma262/#sec-string.prototype.match
    function match(regexp) {
      var O = requireObjectCoercible(this);
      var matcher = regexp == undefined ? undefined : regexp[MATCH];
      return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
    }, // `RegExp.prototype[@@match]` method
    // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@match
    function (regexp) {
      var res = maybeCallNative(nativeMatch, regexp, this);
      if (res.done) return res.value;
      var rx = anObject(regexp);
      var S = String(this);
      if (!rx.global) return regexpExecAbstract(rx, S);
      var fullUnicode = rx.unicode;
      rx.lastIndex = 0;
      var A = [];
      var n = 0;
      var result;

      while ((result = regexpExecAbstract(rx, S)) !== null) {
        var matchStr = String(result[0]);
        A[n] = matchStr;
        if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
        n++;
      }

      return n === 0 ? null : A;
    }];
  });

  function _assertThisInitialized(self) {
    if (self === void 0) {
      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }

    return self;
  }

  function _possibleConstructorReturn(self, call) {
    if (call && (_typeof(call) === "object" || typeof call === "function")) {
      return call;
    }

    return _assertThisInitialized(self);
  }

  function _getPrototypeOf(o) {
    _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
      return o.__proto__ || Object.getPrototypeOf(o);
    };
    return _getPrototypeOf(o);
  }

  function _superPropBase(object, property) {
    while (!Object.prototype.hasOwnProperty.call(object, property)) {
      object = _getPrototypeOf(object);
      if (object === null) break;
    }

    return object;
  }

  function _get(target, property, receiver) {
    if (typeof Reflect !== "undefined" && Reflect.get) {
      _get = Reflect.get;
    } else {
      _get = function _get(target, property, receiver) {
        var base = _superPropBase(target, property);

        if (!base) return;
        var desc = Object.getOwnPropertyDescriptor(base, property);

        if (desc.get) {
          return desc.get.call(receiver);
        }

        return desc.value;
      };
    }

    return _get(target, property, receiver || target);
  }

  function _setPrototypeOf(o, p) {
    _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
      o.__proto__ = p;
      return o;
    };

    return _setPrototypeOf(o, p);
  }

  function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
      throw new TypeError("Super expression must either be null or a function");
    }

    subClass.prototype = Object.create(superClass && superClass.prototype, {
      constructor: {
        value: subClass,
        writable: true,
        configurable: true
      }
    });
    if (superClass) _setPrototypeOf(subClass, superClass);
  }

  var getOwnPropertyNames = objectGetOwnPropertyNames.f;
  var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
  var defineProperty$5 = objectDefineProperty.f;
  var trim$1 = stringTrim.trim;
  var NUMBER = 'Number';
  var NativeNumber = global_1[NUMBER];
  var NumberPrototype = NativeNumber.prototype; // Opera ~12 has broken Object#toString

  var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER; // `ToNumber` abstract operation
  // https://tc39.github.io/ecma262/#sec-tonumber

  var toNumber = function (argument) {
    var it = toPrimitive(argument, false);
    var first, third, radix, maxCode, digits, length, index, code;

    if (typeof it == 'string' && it.length > 2) {
      it = trim$1(it);
      first = it.charCodeAt(0);

      if (first === 43 || first === 45) {
        third = it.charCodeAt(2);
        if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
      } else if (first === 48) {
        switch (it.charCodeAt(1)) {
          case 66:
          case 98:
            radix = 2;
            maxCode = 49;
            break;
          // fast equal of /^0b[01]+$/i

          case 79:
          case 111:
            radix = 8;
            maxCode = 55;
            break;
          // fast equal of /^0o[0-7]+$/i

          default:
            return +it;
        }

        digits = it.slice(2);
        length = digits.length;

        for (index = 0; index < length; index++) {
          code = digits.charCodeAt(index); // parseInt parses a string to a first unavailable symbol
          // but ToNumber should return NaN if a string contains unavailable symbols

          if (code < 48 || code > maxCode) return NaN;
        }

        return parseInt(digits, radix);
      }
    }

    return +it;
  }; // `Number` constructor
  // https://tc39.github.io/ecma262/#sec-number-constructor


  if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
    var NumberWrapper = function Number(value) {
      var it = arguments.length < 1 ? 0 : value;
      var dummy = this;
      return dummy instanceof NumberWrapper // check on 1..constructor(foo) case
      && (BROKEN_CLASSOF ? fails(function () {
        NumberPrototype.valueOf.call(dummy);
      }) : classofRaw(dummy) != NUMBER) ? inheritIfRequired(new NativeNumber(toNumber(it)), dummy, NumberWrapper) : toNumber(it);
    };

    for (var keys$1 = descriptors ? getOwnPropertyNames(NativeNumber) : ( // ES3:
    'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' + // ES2015 (in case, if modules with ES2015 Number statics required before):
    'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' + 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger').split(','), j = 0, key; keys$1.length > j; j++) {
      if (has(NativeNumber, key = keys$1[j]) && !has(NumberWrapper, key)) {
        defineProperty$5(NumberWrapper, key, getOwnPropertyDescriptor$2(NativeNumber, key));
      }
    }

    NumberWrapper.prototype = NumberPrototype;
    NumberPrototype.constructor = NumberWrapper;
    redefine(global_1, NUMBER, NumberWrapper);
  }

  var trim$2 = stringTrim.trim;
  var nativeParseFloat = global_1.parseFloat;
  var FORCED$2 = 1 / nativeParseFloat(whitespaces + '-0') !== -Infinity; // `parseFloat` method
  // https://tc39.github.io/ecma262/#sec-parsefloat-string

  var _parseFloat = FORCED$2 ? function parseFloat(string) {
    var trimmedString = trim$2(String(string));
    var result = nativeParseFloat(trimmedString);
    return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
  } : nativeParseFloat; // `parseFloat` method
  // https://tc39.github.io/ecma262/#sec-parsefloat-string


  _export({
    global: true,
    forced: parseFloat != _parseFloat
  }, {
    parseFloat: _parseFloat
  });

  var Point = /*#__PURE__*/function () {
    // Initialize
    function Point() {
      _classCallCheck(this, Point);

      this.init.apply(this, arguments);
    }

    _createClass(Point, [{
      key: "init",
      value: function init(x, y) {
        var base = {
          x: 0,
          y: 0
        }; // ensure source as object

        var source = Array.isArray(x) ? {
          x: x[0],
          y: x[1]
        } : _typeof(x) === 'object' ? {
          x: x.x,
          y: x.y
        } : {
          x: x,
          y: y
        }; // merge source

        this.x = source.x == null ? base.x : source.x;
        this.y = source.y == null ? base.y : source.y;
        return this;
      } // Clone point

    }, {
      key: "clone",
      value: function clone() {
        return new Point(this);
      }
    }, {
      key: "transform",
      value: function transform(m) {
        return this.clone().transformO(m);
      } // Transform point with matrix

    }, {
      key: "transformO",
      value: function transformO(m) {
        if (!Matrix.isMatrixLike(m)) {
          m = new Matrix(m);
        }

        var x = this.x,
            y = this.y; // Perform the matrix multiplication

        this.x = m.a * x + m.c * y + m.e;
        this.y = m.b * x + m.d * y + m.f;
        return this;
      }
    }, {
      key: "toArray",
      value: function toArray() {
        return [this.x, this.y];
      }
    }]);

    return Point;
  }();

  function point(x, y) {
    return new Point(x, y).transform(this.screenCTM().inverse());
  }

  function closeEnough(a, b, threshold) {
    return Math.abs(b - a) < (threshold || 1e-6);
  }

  var Matrix = /*#__PURE__*/function () {
    function Matrix() {
      _classCallCheck(this, Matrix);

      this.init.apply(this, arguments);
    } // Initialize


    _createClass(Matrix, [{
      key: "init",
      value: function init(source) {
        var base = Matrix.fromArray([1, 0, 0, 1, 0, 0]); // ensure source as object

        source = source instanceof Element ? source.matrixify() : typeof source === 'string' ? Matrix.fromArray(source.split(delimiter).map(parseFloat)) : Array.isArray(source) ? Matrix.fromArray(source) : _typeof(source) === 'object' && Matrix.isMatrixLike(source) ? source : _typeof(source) === 'object' ? new Matrix().transform(source) : arguments.length === 6 ? Matrix.fromArray([].slice.call(arguments)) : base; // Merge the source matrix with the base matrix

        this.a = source.a != null ? source.a : base.a;
        this.b = source.b != null ? source.b : base.b;
        this.c = source.c != null ? source.c : base.c;
        this.d = source.d != null ? source.d : base.d;
        this.e = source.e != null ? source.e : base.e;
        this.f = source.f != null ? source.f : base.f;
        return this;
      } // Clones this matrix

    }, {
      key: "clone",
      value: function clone() {
        return new Matrix(this);
      } // Transform a matrix into another matrix by manipulating the space

    }, {
      key: "transform",
      value: function transform(o) {
        // Check if o is a matrix and then left multiply it directly
        if (Matrix.isMatrixLike(o)) {
          var matrix = new Matrix(o);
          return matrix.multiplyO(this);
        } // Get the proposed transformations and the current transformations


        var t = Matrix.formatTransforms(o);
        var current = this;

        var _transform = new Point(t.ox, t.oy).transform(current),
            ox = _transform.x,
            oy = _transform.y; // Construct the resulting matrix


        var transformer = new Matrix().translateO(t.rx, t.ry).lmultiplyO(current).translateO(-ox, -oy).scaleO(t.scaleX, t.scaleY).skewO(t.skewX, t.skewY).shearO(t.shear).rotateO(t.theta).translateO(ox, oy); // If we want the origin at a particular place, we force it there

        if (isFinite(t.px) || isFinite(t.py)) {
          var origin = new Point(ox, oy).transform(transformer); // TODO: Replace t.px with isFinite(t.px)

          var dx = t.px ? t.px - origin.x : 0;
          var dy = t.py ? t.py - origin.y : 0;
          transformer.translateO(dx, dy);
        } // Translate now after positioning


        transformer.translateO(t.tx, t.ty);
        return transformer;
      } // Applies a matrix defined by its affine parameters

    }, {
      key: "compose",
      value: function compose(o) {
        if (o.origin) {
          o.originX = o.origin[0];
          o.originY = o.origin[1];
        } // Get the parameters


        var ox = o.originX || 0;
        var oy = o.originY || 0;
        var sx = o.scaleX || 1;
        var sy = o.scaleY || 1;
        var lam = o.shear || 0;
        var theta = o.rotate || 0;
        var tx = o.translateX || 0;
        var ty = o.translateY || 0; // Apply the standard matrix

        var result = new Matrix().translateO(-ox, -oy).scaleO(sx, sy).shearO(lam).rotateO(theta).translateO(tx, ty).lmultiplyO(this).translateO(ox, oy);
        return result;
      } // Decomposes this matrix into its affine parameters

    }, {
      key: "decompose",
      value: function decompose() {
        var cx = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        var cy = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; // Get the parameters from the matrix

        var a = this.a;
        var b = this.b;
        var c = this.c;
        var d = this.d;
        var e = this.e;
        var f = this.f; // Figure out if the winding direction is clockwise or counterclockwise

        var determinant = a * d - b * c;
        var ccw = determinant > 0 ? 1 : -1; // Since we only shear in x, we can use the x basis to get the x scale
        // and the rotation of the resulting matrix

        var sx = ccw * Math.sqrt(a * a + b * b);
        var thetaRad = Math.atan2(ccw * b, ccw * a);
        var theta = 180 / Math.PI * thetaRad;
        var ct = Math.cos(thetaRad);
        var st = Math.sin(thetaRad); // We can then solve the y basis vector simultaneously to get the other
        // two affine parameters directly from these parameters

        var lam = (a * c + b * d) / determinant;
        var sy = c * sx / (lam * a - b) || d * sx / (lam * b + a); // Use the translations

        var tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy);
        var ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy); // Construct the decomposition and return it

        return {
          // Return the affine parameters
          scaleX: sx,
          scaleY: sy,
          shear: lam,
          rotate: theta,
          translateX: tx,
          translateY: ty,
          originX: cx,
          originY: cy,
          // Return the matrix parameters
          a: this.a,
          b: this.b,
          c: this.c,
          d: this.d,
          e: this.e,
          f: this.f
        };
      } // Left multiplies by the given matrix

    }, {
      key: "multiply",
      value: function multiply(matrix) {
        return this.clone().multiplyO(matrix);
      }
    }, {
      key: "multiplyO",
      value: function multiplyO(matrix) {
        // Get the matrices
        var l = this;
        var r = matrix instanceof Matrix ? matrix : new Matrix(matrix);
        return Matrix.matrixMultiply(l, r, this);
      }
    }, {
      key: "lmultiply",
      value: function lmultiply(matrix) {
        return this.clone().lmultiplyO(matrix);
      }
    }, {
      key: "lmultiplyO",
      value: function lmultiplyO(matrix) {
        var r = this;
        var l = matrix instanceof Matrix ? matrix : new Matrix(matrix);
        return Matrix.matrixMultiply(l, r, this);
      } // Inverses matrix

    }, {
      key: "inverseO",
      value: function inverseO() {
        // Get the current parameters out of the matrix
        var a = this.a;
        var b = this.b;
        var c = this.c;
        var d = this.d;
        var e = this.e;
        var f = this.f; // Invert the 2x2 matrix in the top left

        var det = a * d - b * c;
        if (!det) throw new Error('Cannot invert ' + this); // Calculate the top 2x2 matrix

        var na = d / det;
        var nb = -b / det;
        var nc = -c / det;
        var nd = a / det; // Apply the inverted matrix to the top right

        var ne = -(na * e + nc * f);
        var nf = -(nb * e + nd * f); // Construct the inverted matrix

        this.a = na;
        this.b = nb;
        this.c = nc;
        this.d = nd;
        this.e = ne;
        this.f = nf;
        return this;
      }
    }, {
      key: "inverse",
      value: function inverse() {
        return this.clone().inverseO();
      } // Translate matrix

    }, {
      key: "translate",
      value: function translate(x, y) {
        return this.clone().translateO(x, y);
      }
    }, {
      key: "translateO",
      value: function translateO(x, y) {
        this.e += x || 0;
        this.f += y || 0;
        return this;
      } // Scale matrix

    }, {
      key: "scale",
      value: function scale(x, y, cx, cy) {
        var _this$clone;

        return (_this$clone = this.clone()).scaleO.apply(_this$clone, arguments);
      }
    }, {
      key: "scaleO",
      value: function scaleO(x) {
        var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
        var cx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
        var cy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; // Support uniform scaling

        if (arguments.length === 3) {
          cy = cx;
          cx = y;
          y = x;
        }

        var a = this.a,
            b = this.b,
            c = this.c,
            d = this.d,
            e = this.e,
            f = this.f;
        this.a = a * x;
        this.b = b * y;
        this.c = c * x;
        this.d = d * y;
        this.e = e * x - cx * x + cx;
        this.f = f * y - cy * y + cy;
        return this;
      } // Rotate matrix

    }, {
      key: "rotate",
      value: function rotate(r, cx, cy) {
        return this.clone().rotateO(r, cx, cy);
      }
    }, {
      key: "rotateO",
      value: function rotateO(r) {
        var cx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
        var cy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; // Convert degrees to radians

        r = radians(r);
        var cos = Math.cos(r);
        var sin = Math.sin(r);
        var a = this.a,
            b = this.b,
            c = this.c,
            d = this.d,
            e = this.e,
            f = this.f;
        this.a = a * cos - b * sin;
        this.b = b * cos + a * sin;
        this.c = c * cos - d * sin;
        this.d = d * cos + c * sin;
        this.e = e * cos - f * sin + cy * sin - cx * cos + cx;
        this.f = f * cos + e * sin - cx * sin - cy * cos + cy;
        return this;
      } // Flip matrix on x or y, at a given offset

    }, {
      key: "flip",
      value: function flip(axis, around) {
        return this.clone().flipO(axis, around);
      }
    }, {
      key: "flipO",
      value: function flipO(axis, around) {
        return axis === 'x' ? this.scaleO(-1, 1, around, 0) : axis === 'y' ? this.scaleO(1, -1, 0, around) : this.scaleO(-1, -1, axis, around || axis); // Define an x, y flip point
      } // Shear matrix

    }, {
      key: "shear",
      value: function shear(a, cx, cy) {
        return this.clone().shearO(a, cx, cy);
      }
    }, {
      key: "shearO",
      value: function shearO(lx) {
        var cy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
        var a = this.a,
            b = this.b,
            c = this.c,
            d = this.d,
            e = this.e,
            f = this.f;
        this.a = a + b * lx;
        this.c = c + d * lx;
        this.e = e + f * lx - cy * lx;
        return this;
      } // Skew Matrix

    }, {
      key: "skew",
      value: function skew(x, y, cx, cy) {
        var _this$clone2;

        return (_this$clone2 = this.clone()).skewO.apply(_this$clone2, arguments);
      }
    }, {
      key: "skewO",
      value: function skewO(x) {
        var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
        var cx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
        var cy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; // support uniformal skew

        if (arguments.length === 3) {
          cy = cx;
          cx = y;
          y = x;
        } // Convert degrees to radians


        x = radians(x);
        y = radians(y);
        var lx = Math.tan(x);
        var ly = Math.tan(y);
        var a = this.a,
            b = this.b,
            c = this.c,
            d = this.d,
            e = this.e,
            f = this.f;
        this.a = a + b * lx;
        this.b = b + a * ly;
        this.c = c + d * lx;
        this.d = d + c * ly;
        this.e = e + f * lx - cy * lx;
        this.f = f + e * ly - cx * ly;
        return this;
      } // SkewX

    }, {
      key: "skewX",
      value: function skewX(x, cx, cy) {
        return this.skew(x, 0, cx, cy);
      }
    }, {
      key: "skewXO",
      value: function skewXO(x, cx, cy) {
        return this.skewO(x, 0, cx, cy);
      } // SkewY

    }, {
      key: "skewY",
      value: function skewY(y, cx, cy) {
        return this.skew(0, y, cx, cy);
      }
    }, {
      key: "skewYO",
      value: function skewYO(y, cx, cy) {
        return this.skewO(0, y, cx, cy);
      } // Transform around a center point

    }, {
      key: "aroundO",
      value: function aroundO(cx, cy, matrix) {
        var dx = cx || 0;
        var dy = cy || 0;
        return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy);
      }
    }, {
      key: "around",
      value: function around(cx, cy, matrix) {
        return this.clone().aroundO(cx, cy, matrix);
      } // Check if two matrices are equal

    }, {
      key: "equals",
      value: function equals(other) {
        var comp = new Matrix(other);
        return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) && closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) && closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f);
      } // Convert matrix to string

    }, {
      key: "toString",
      value: function toString() {
        return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')';
      }
    }, {
      key: "toArray",
      value: function toArray() {
        return [this.a, this.b, this.c, this.d, this.e, this.f];
      }
    }, {
      key: "valueOf",
      value: function valueOf() {
        return {
          a: this.a,
          b: this.b,
          c: this.c,
          d: this.d,
          e: this.e,
          f: this.f
        };
      }
    }], [{
      key: "fromArray",
      value: function fromArray(a) {
        return {
          a: a[0],
          b: a[1],
          c: a[2],
          d: a[3],
          e: a[4],
          f: a[5]
        };
      }
    }, {
      key: "isMatrixLike",
      value: function isMatrixLike(o) {
        return o.a != null || o.b != null || o.c != null || o.d != null || o.e != null || o.f != null;
      }
    }, {
      key: "formatTransforms",
      value: function formatTransforms(o) {
        // Get all of the parameters required to form the matrix
        var flipBoth = o.flip === 'both' || o.flip === true;
        var flipX = o.flip && (flipBoth || o.flip === 'x') ? -1 : 1;
        var flipY = o.flip && (flipBoth || o.flip === 'y') ? -1 : 1;
        var skewX = o.skew && o.skew.length ? o.skew[0] : isFinite(o.skew) ? o.skew : isFinite(o.skewX) ? o.skewX : 0;
        var skewY = o.skew && o.skew.length ? o.skew[1] : isFinite(o.skew) ? o.skew : isFinite(o.skewY) ? o.skewY : 0;
        var scaleX = o.scale && o.scale.length ? o.scale[0] * flipX : isFinite(o.scale) ? o.scale * flipX : isFinite(o.scaleX) ? o.scaleX * flipX : flipX;
        var scaleY = o.scale && o.scale.length ? o.scale[1] * flipY : isFinite(o.scale) ? o.scale * flipY : isFinite(o.scaleY) ? o.scaleY * flipY : flipY;
        var shear = o.shear || 0;
        var theta = o.rotate || o.theta || 0;
        var origin = new Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY);
        var ox = origin.x;
        var oy = origin.y;
        var position = new Point(o.position || o.px || o.positionX, o.py || o.positionY);
        var px = position.x;
        var py = position.y;
        var translate = new Point(o.translate || o.tx || o.translateX, o.ty || o.translateY);
        var tx = translate.x;
        var ty = translate.y;
        var relative = new Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY);
        var rx = relative.x;
        var ry = relative.y; // Populate all of the values

        return {
          scaleX: scaleX,
          scaleY: scaleY,
          skewX: skewX,
          skewY: skewY,
          shear: shear,
          theta: theta,
          rx: rx,
          ry: ry,
          tx: tx,
          ty: ty,
          ox: ox,
          oy: oy,
          px: px,
          py: py
        };
      } // left matrix, right matrix, target matrix which is overwritten

    }, {
      key: "matrixMultiply",
      value: function matrixMultiply(l, r, o) {
        // Work out the product directly
        var a = l.a * r.a + l.c * r.b;
        var b = l.b * r.a + l.d * r.b;
        var c = l.a * r.c + l.c * r.d;
        var d = l.b * r.c + l.d * r.d;
        var e = l.e + l.a * r.e + l.c * r.f;
        var f = l.f + l.b * r.e + l.d * r.f; // make sure to use local variables because l/r and o could be the same

        o.a = a;
        o.b = b;
        o.c = c;
        o.d = d;
        o.e = e;
        o.f = f;
        return o;
      }
    }]);

    return Matrix;
  }();

  function ctm() {
    return new Matrix(this.node.getCTM());
  }

  function screenCTM() {
    /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537
       This is needed because FF does not return the transformation matrix
       for the inner coordinate system when getScreenCTM() is called on nested svgs.
       However all other Browsers do that */
    if (typeof this.isRoot === 'function' && !this.isRoot()) {
      var rect = this.rect(1, 1);
      var m = rect.node.getScreenCTM();
      rect.remove();
      return new Matrix(m);
    }

    return new Matrix(this.node.getScreenCTM());
  }

  register(Matrix, 'Matrix');

  function parser() {
    // Reuse cached element if possible
    if (!parser.nodes) {
      var svg = makeInstance().size(2, 0);
      svg.node.style.cssText = ['opacity: 0', 'position: absolute', 'left: -100%', 'top: -100%', 'overflow: hidden'].join(';');
      svg.attr('focusable', 'false');
      svg.attr('aria-hidden', 'true');
      var path = svg.path().node;
      parser.nodes = {
        svg: svg,
        path: path
      };
    }

    if (!parser.nodes.svg.node.parentNode) {
      var b = globals.document.body || globals.document.documentElement;
      parser.nodes.svg.addTo(b);
    }

    return parser.nodes;
  }

  function isNulledBox(box) {
    return !box.width && !box.height && !box.x && !box.y;
  }

  function domContains(node) {
    return node === globals.document || (globals.document.documentElement.contains || function (node) {
      // This is IE - it does not support contains() for top-level SVGs
      while (node.parentNode) {
        node = node.parentNode;
      }

      return node === globals.document;
    }).call(globals.document.documentElement, node);
  }

  var Box = /*#__PURE__*/function () {
    function Box() {
      _classCallCheck(this, Box);

      this.init.apply(this, arguments);
    }

    _createClass(Box, [{
      key: "init",
      value: function init(source) {
        var base = [0, 0, 0, 0];
        source = typeof source === 'string' ? source.split(delimiter).map(parseFloat) : Array.isArray(source) ? source : _typeof(source) === 'object' ? [source.left != null ? source.left : source.x, source.top != null ? source.top : source.y, source.width, source.height] : arguments.length === 4 ? [].slice.call(arguments) : base;
        this.x = source[0] || 0;
        this.y = source[1] || 0;
        this.width = this.w = source[2] || 0;
        this.height = this.h = source[3] || 0; // Add more bounding box properties

        this.x2 = this.x + this.w;
        this.y2 = this.y + this.h;
        this.cx = this.x + this.w / 2;
        this.cy = this.y + this.h / 2;
        return this;
      } // Merge rect box with another, return a new instance

    }, {
      key: "merge",
      value: function merge(box) {
        var x = Math.min(this.x, box.x);
        var y = Math.min(this.y, box.y);
        var width = Math.max(this.x + this.width, box.x + box.width) - x;
        var height = Math.max(this.y + this.height, box.y + box.height) - y;
        return new Box(x, y, width, height);
      }
    }, {
      key: "transform",
      value: function transform(m) {
        if (!(m instanceof Matrix)) {
          m = new Matrix(m);
        }

        var xMin = Infinity;
        var xMax = -Infinity;
        var yMin = Infinity;
        var yMax = -Infinity;
        var pts = [new Point(this.x, this.y), new Point(this.x2, this.y), new Point(this.x, this.y2), new Point(this.x2, this.y2)];
        pts.forEach(function (p) {
          p = p.transform(m);
          xMin = Math.min(xMin, p.x);
          xMax = Math.max(xMax, p.x);
          yMin = Math.min(yMin, p.y);
          yMax = Math.max(yMax, p.y);
        });
        return new Box(xMin, yMin, xMax - xMin, yMax - yMin);
      }
    }, {
      key: "addOffset",
      value: function addOffset() {
        // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
        this.x += globals.window.pageXOffset;
        this.y += globals.window.pageYOffset;
        return this;
      }
    }, {
      key: "toString",
      value: function toString() {
        return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height;
      }
    }, {
      key: "toArray",
      value: function toArray() {
        return [this.x, this.y, this.width, this.height];
      }
    }, {
      key: "isNulled",
      value: function isNulled() {
        return isNulledBox(this);
      }
    }]);

    return Box;
  }();

  function getBox(cb, retry) {
    var box;

    try {
      box = cb(this.node);

      if (isNulledBox(box) && !domContains(this.node)) {
        throw new Error('Element not in the dom');
      }
    } catch (e) {
      box = retry(this);
    }

    return box;
  }

  function bbox() {
    return new Box(getBox.call(this, function (node) {
      return node.getBBox();
    }, function (el) {
      try {
        var clone = el.clone().addTo(parser().svg).show();
        var box = clone.node.getBBox();
        clone.remove();
        return box;
      } catch (e) {
        throw new Error('Getting bbox of element "' + el.node.nodeName + '" is not possible. ' + e.toString());
      }
    }));
  }

  function rbox(el) {
    var box = new Box(getBox.call(this, function (node) {
      return node.getBoundingClientRect();
    }, function (el) {
      throw new Error('Getting rbox of element "' + el.node.nodeName + '" is not possible');
    }));
    if (el) return box.transform(el.screenCTM().inverse());
    return box.addOffset();
  }

  registerMethods({
    viewbox: {
      viewbox: function viewbox(x, y, width, height) {
        // act as getter
        if (x == null) return new Box(this.attr('viewBox')); // act as setter

        return this.attr('viewBox', new Box(x, y, width, height));
      },
      zoom: function zoom(level, point) {
        var width = this.node.clientWidth;
        var height = this.node.clientHeight;
        var v = this.viewbox(); // Firefox does not support clientHeight and returns 0
        // https://bugzilla.mozilla.org/show_bug.cgi?id=874811

        if (!width && !height) {
          var style = window.getComputedStyle(this.node);
          width = parseFloat(style.getPropertyValue('width'));
          height = parseFloat(style.getPropertyValue('height'));
        }

        var zoomX = width / v.width;
        var zoomY = height / v.height;
        var zoom = Math.min(zoomX, zoomY);

        if (level == null) {
          return zoom;
        }

        var zoomAmount = zoom / level;
        if (zoomAmount === Infinity) zoomAmount = Number.MIN_VALUE;
        point = point || new Point(width / 2 / zoomX + v.x, height / 2 / zoomY + v.y);
        var box = new Box(v).transform(new Matrix({
          scale: zoomAmount,
          origin: point
        }));
        return this.viewbox(box);
      }
    }
  });
  register(Box, 'Box');
  /* eslint no-new-func: "off" */

  var subClassArray = function () {
    try {
      // try es6 subclassing
      return Function('name', 'baseClass', '_constructor', ['baseClass = baseClass || Array', 'return {', '  [name]: class extends baseClass {', '    constructor (...args) {', '      super(...args)', '      _constructor && _constructor.apply(this, args)', '    }', '  }', '}[name]'].join('\n'));
    } catch (e) {
      // Use es5 approach
      return function (name) {
        var baseClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Array;

        var _constructor = arguments.length > 2 ? arguments[2] : undefined;

        var Arr = function Arr() {
          baseClass.apply(this, arguments);
          _constructor && _constructor.apply(this, arguments);
        };

        Arr.prototype = Object.create(baseClass.prototype);
        Arr.prototype.constructor = Arr;

        Arr.prototype.map = function (fn) {
          var arr = new Arr();
          arr.push.apply(arr, Array.prototype.map.call(this, fn));
          return arr;
        };

        return Arr;
      };
    }
  }();

  var List = subClassArray('List', Array, function () {
    var arr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; // This catches the case, that native map tries to create an array with new Array(1)

    if (typeof arr === 'number') return this;
    this.length = 0;
    this.push.apply(this, _toConsumableArray(arr));
  });
  extend(List, {
    each: function each(fnOrMethodName) {
      for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
        args[_key - 1] = arguments[_key];
      }

      if (typeof fnOrMethodName === 'function') {
        return this.map(function (el) {
          return fnOrMethodName.call(el, el);
        });
      } else {
        return this.map(function (el) {
          return el[fnOrMethodName].apply(el, args);
        });
      }
    },
    toArray: function toArray() {
      return Array.prototype.concat.apply([], this);
    }
  });
  var reserved = ['toArray', 'constructor', 'each'];

  List.extend = function (methods) {
    methods = methods.reduce(function (obj, name) {
      // Don't overwrite own methods
      if (reserved.includes(name)) return obj; // Don't add private methods

      if (name[0] === '_') return obj; // Relay every call to each()

      obj[name] = function () {
        for (var _len2 = arguments.length, attrs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
          attrs[_key2] = arguments[_key2];
        }

        return this.each.apply(this, [name].concat(attrs));
      };

      return obj;
    }, {});
    extend(List, methods);
  };

  function baseFind(query, parent) {
    return new List(map((parent || globals.document).querySelectorAll(query), function (node) {
      return adopt(node);
    }));
  } // Scoped find method


  function find(query) {
    return baseFind(query, this.node);
  }

  function findOne(query) {
    return adopt(this.node.querySelector(query));
  }

  var EventTarget = /*#__PURE__*/function (_Base) {
    _inherits(EventTarget, _Base);

    function EventTarget() {
      var _this;

      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
          _ref$events = _ref.events,
          events = _ref$events === void 0 ? {} : _ref$events;

      _classCallCheck(this, EventTarget);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(EventTarget).call(this));
      _this.events = events;
      return _this;
    }

    _createClass(EventTarget, [{
      key: "addEventListener",
      value: function addEventListener() {}
    }, {
      key: "dispatch",
      value: function dispatch$1(event, data) {
        return dispatch(this, event, data);
      }
    }, {
      key: "dispatchEvent",
      value: function dispatchEvent(event) {
        var bag = this.getEventHolder().events;
        if (!bag) return true;
        var events = bag[event.type];

        for (var i in events) {
          for (var j in events[i]) {
            events[i][j](event);
          }
        }

        return !event.defaultPrevented;
      } // Fire given event

    }, {
      key: "fire",
      value: function fire(event, data) {
        this.dispatch(event, data);
        return this;
      }
    }, {
      key: "getEventHolder",
      value: function getEventHolder() {
        return this;
      }
    }, {
      key: "getEventTarget",
      value: function getEventTarget() {
        return this;
      } // Unbind event from listener

    }, {
      key: "off",
      value: function off$1(event, listener) {
        off(this, event, listener);
        return this;
      } // Bind given event to listener

    }, {
      key: "on",
      value: function on$1(event, listener, binding, options) {
        on(this, event, listener, binding, options);
        return this;
      }
    }, {
      key: "removeEventListener",
      value: function removeEventListener() {}
    }]);

    return EventTarget;
  }(Base);

  register(EventTarget, 'EventTarget');

  function noop() {} // Default animation values


  var timeline = {
    duration: 400,
    ease: '>',
    delay: 0
  }; // Default attribute values

  var attrs = {
    // fill and stroke
    'fill-opacity': 1,
    'stroke-opacity': 1,
    'stroke-width': 0,
    'stroke-linejoin': 'miter',
    'stroke-linecap': 'butt',
    fill: '#000000',
    stroke: '#000000',
    opacity: 1,
    // position
    x: 0,
    y: 0,
    cx: 0,
    cy: 0,
    // size
    width: 0,
    height: 0,
    // radius
    r: 0,
    rx: 0,
    ry: 0,
    // gradient
    offset: 0,
    'stop-opacity': 1,
    'stop-color': '#000000',
    // text
    'text-anchor': 'start'
  };
  var defaults = {
    __proto__: null,
    noop: noop,
    timeline: timeline,
    attrs: attrs
  };
  var SVGArray = subClassArray('SVGArray', Array, function (arr) {
    this.init(arr);
  });
  extend(SVGArray, {
    init: function init(arr) {
      // This catches the case, that native map tries to create an array with new Array(1)
      if (typeof arr === 'number') return this;
      this.length = 0;
      this.push.apply(this, _toConsumableArray(this.parse(arr)));
      return this;
    },
    toArray: function toArray() {
      return Array.prototype.concat.apply([], this);
    },
    toString: function toString() {
      return this.join(' ');
    },
    // Flattens the array if needed
    valueOf: function valueOf() {
      var ret = [];
      ret.push.apply(ret, _toConsumableArray(this));
      return ret;
    },
    // Parse whitespace separated string
    parse: function parse() {
      var array = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; // If already is an array, no need to parse it

      if (array instanceof Array) return array;
      return array.trim().split(delimiter).map(parseFloat);
    },
    clone: function clone() {
      return new this.constructor(this);
    },
    toSet: function toSet() {
      return new Set(this);
    }
  });

  var SVGNumber = /*#__PURE__*/function () {
    // Initialize
    function SVGNumber() {
      _classCallCheck(this, SVGNumber);

      this.init.apply(this, arguments);
    }

    _createClass(SVGNumber, [{
      key: "init",
      value: function init(value, unit) {
        unit = Array.isArray(value) ? value[1] : unit;
        value = Array.isArray(value) ? value[0] : value; // initialize defaults

        this.value = 0;
        this.unit = unit || ''; // parse value

        if (typeof value === 'number') {
          // ensure a valid numeric value
          this.value = isNaN(value) ? 0 : !isFinite(value) ? value < 0 ? -3.4e+38 : +3.4e+38 : value;
        } else if (typeof value === 'string') {
          unit = value.match(numberAndUnit);

          if (unit) {
            // make value numeric
            this.value = parseFloat(unit[1]); // normalize

            if (unit[5] === '%') {
              this.value /= 100;
            } else if (unit[5] === 's') {
              this.value *= 1000;
            } // store unit


            this.unit = unit[5];
          }
        } else {
          if (value instanceof SVGNumber) {
            this.value = value.valueOf();
            this.unit = value.unit;
          }
        }

        return this;
      }
    }, {
      key: "toString",
      value: function toString() {
        return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6 : this.unit === 's' ? this.value / 1e3 : this.value) + this.unit;
      }
    }, {
      key: "toJSON",
      value: function toJSON() {
        return this.toString();
      }
    }, {
      key: "toArray",
      value: function toArray() {
        return [this.value, this.unit];
      }
    }, {
      key: "valueOf",
      value: function valueOf() {
        return this.value;
      } // Add number

    }, {
      key: "plus",
      value: function plus(number) {
        number = new SVGNumber(number);
        return new SVGNumber(this + number, this.unit || number.unit);
      } // Subtract number

    }, {
      key: "minus",
      value: function minus(number) {
        number = new SVGNumber(number);
        return new SVGNumber(this - number, this.unit || number.unit);
      } // Multiply number

    }, {
      key: "times",
      value: function times(number) {
        number = new SVGNumber(number);
        return new SVGNumber(this * number, this.unit || number.unit);
      } // Divide number

    }, {
      key: "divide",
      value: function divide(number) {
        number = new SVGNumber(number);
        return new SVGNumber(this / number, this.unit || number.unit);
      }
    }, {
      key: "convert",
      value: function convert(unit) {
        return new SVGNumber(this.value, unit);
      }
    }]);

    return SVGNumber;
  }();

  var hooks = [];

  function registerAttrHook(fn) {
    hooks.push(fn);
  } // Set svg element attribute


  function attr(attr, val, ns) {
    var _this = this; // act as full getter


    if (attr == null) {
      // get an object of attributes
      attr = {};
      val = this.node.attributes;
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = val[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var node = _step.value;
          attr[node.nodeName] = isNumber.test(node.nodeValue) ? parseFloat(node.nodeValue) : node.nodeValue;
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return attr;
    } else if (attr instanceof Array) {
      // loop through array and get all values
      return attr.reduce(function (last, curr) {
        last[curr] = _this.attr(curr);
        return last;
      }, {});
    } else if (_typeof(attr) === 'object' && attr.constructor === Object) {
      // apply every attribute individually if an object is passed
      for (val in attr) {
        this.attr(val, attr[val]);
      }
    } else if (val === null) {
      // remove value
      this.node.removeAttribute(attr);
    } else if (val == null) {
      // act as a getter if the first and only argument is not an object
      val = this.node.getAttribute(attr);
      return val == null ? attrs[attr] : isNumber.test(val) ? parseFloat(val) : val;
    } else {
      // Loop through hooks and execute them to convert value
      val = hooks.reduce(function (_val, hook) {
        return hook(attr, _val, _this);
      }, val); // ensure correct numeric values (also accepts NaN and Infinity)

      if (typeof val === 'number') {
        val = new SVGNumber(val);
      } else if (Color.isColor(val)) {
        // ensure full hex color
        val = new Color(val);
      } else if (val.constructor === Array) {
        // Check for plain arrays and parse array values
        val = new SVGArray(val);
      } // if the passed attribute is leading...


      if (attr === 'leading') {
        // ... call the leading method instead
        if (this.leading) {
          this.leading(val);
        }
      } else {
        // set given attribute on node
        typeof ns === 'string' ? this.node.setAttributeNS(ns, attr, val.toString()) : this.node.setAttribute(attr, val.toString());
      } // rebuild if required


      if (this.rebuild && (attr === 'font-size' || attr === 'x')) {
        this.rebuild();
      }
    }

    return this;
  }

  var Dom = /*#__PURE__*/function (_EventTarget) {
    _inherits(Dom, _EventTarget);

    function Dom(node, attrs) {
      var _this2;

      _classCallCheck(this, Dom);

      _this2 = _possibleConstructorReturn(this, _getPrototypeOf(Dom).call(this, node));
      _this2.node = node;
      _this2.type = node.nodeName;

      if (attrs && node !== attrs) {
        _this2.attr(attrs);
      }

      return _this2;
    } // Add given element at a position


    _createClass(Dom, [{
      key: "add",
      value: function add(element, i) {
        element = makeInstance(element);

        if (i == null) {
          this.node.appendChild(element.node);
        } else if (element.node !== this.node.childNodes[i]) {
          this.node.insertBefore(element.node, this.node.childNodes[i]);
        }

        return this;
      } // Add element to given container and return self

    }, {
      key: "addTo",
      value: function addTo(parent) {
        return makeInstance(parent).put(this);
      } // Returns all child elements

    }, {
      key: "children",
      value: function children() {
        return new List(map(this.node.children, function (node) {
          return adopt(node);
        }));
      } // Remove all elements in this container

    }, {
      key: "clear",
      value: function clear() {
        // remove children
        while (this.node.hasChildNodes()) {
          this.node.removeChild(this.node.lastChild);
        }

        return this;
      } // Clone element

    }, {
      key: "clone",
      value: function clone() {
        // write dom data to the dom so the clone can pickup the data
        this.writeDataToDom(); // clone element and assign new id

        return assignNewId(this.node.cloneNode(true));
      } // Iterates over all children and invokes a given block

    }, {
      key: "each",
      value: function each(block, deep) {
        var children = this.children();
        var i, il;

        for (i = 0, il = children.length; i < il; i++) {
          block.apply(children[i], [i, children]);

          if (deep) {
            children[i].each(block, deep);
          }
        }

        return this;
      }
    }, {
      key: "element",
      value: function element(nodeName) {
        return this.put(new Dom(create(nodeName)));
      } // Get first child

    }, {
      key: "first",
      value: function first() {
        return adopt(this.node.firstChild);
      } // Get a element at the given index

    }, {
      key: "get",
      value: function get(i) {
        return adopt(this.node.childNodes[i]);
      }
    }, {
      key: "getEventHolder",
      value: function getEventHolder() {
        return this.node;
      }
    }, {
      key: "getEventTarget",
      value: function getEventTarget() {
        return this.node;
      } // Checks if the given element is a child

    }, {
      key: "has",
      value: function has(element) {
        return this.index(element) >= 0;
      } // Get / set id

    }, {
      key: "id",
      value: function id(_id) {
        // generate new id if no id set
        if (typeof _id === 'undefined' && !this.node.id) {
          this.node.id = eid(this.type);
        } // dont't set directly width this.node.id to make `null` work correctly


        return this.attr('id', _id);
      } // Gets index of given element

    }, {
      key: "index",
      value: function index(element) {
        return [].slice.call(this.node.childNodes).indexOf(element.node);
      } // Get the last child

    }, {
      key: "last",
      value: function last() {
        return adopt(this.node.lastChild);
      } // matches the element vs a css selector

    }, {
      key: "matches",
      value: function matches(selector) {
        var el = this.node;
        return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector);
      } // Returns the parent element instance

    }, {
      key: "parent",
      value: function parent(type) {
        var parent = this; // check for parent

        if (!parent.node.parentNode) return null; // get parent element

        parent = adopt(parent.node.parentNode);
        if (!type) return parent; // loop trough ancestors if type is given

        while (parent) {
          if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent;
          if (!parent.node.parentNode || parent.node.parentNode.nodeName === '#document' || parent.node.parentNode.nodeName === '#document-fragment') return null; // #759, #720

          parent = adopt(parent.node.parentNode);
        }
      } // Basically does the same as `add()` but returns the added element instead

    }, {
      key: "put",
      value: function put(element, i) {
        this.add(element, i);
        return element;
      } // Add element to given container and return container

    }, {
      key: "putIn",
      value: function putIn(parent) {
        return makeInstance(parent).add(this);
      } // Remove element

    }, {
      key: "remove",
      value: function remove() {
        if (this.parent()) {
          this.parent().removeElement(this);
        }

        return this;
      } // Remove a given child

    }, {
      key: "removeElement",
      value: function removeElement(element) {
        this.node.removeChild(element.node);
        return this;
      } // Replace this with element

    }, {
      key: "replace",
      value: function replace(element) {
        element = makeInstance(element);
        this.node.parentNode.replaceChild(element.node, this.node);
        return element;
      }
    }, {
      key: "round",
      value: function round() {
        var precision = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 2;
        var map = arguments.length > 1 ? arguments[1] : undefined;
        var factor = Math.pow(10, precision);
        var attrs = this.attr(); // If we have no map, build one from attrs

        if (!map) {
          map = Object.keys(attrs);
        } // Holds rounded attributes


        var newAttrs = {};
        map.forEach(function (key) {
          newAttrs[key] = Math.round(attrs[key] * factor) / factor;
        });
        this.attr(newAttrs);
        return this;
      } // Return id on string conversion

    }, {
      key: "toString",
      value: function toString() {
        return this.id();
      } // Import raw svg

    }, {
      key: "svg",
      value: function svg(svgOrFn, outerHTML) {
        var well, len, fragment;

        if (svgOrFn === false) {
          outerHTML = false;
          svgOrFn = null;
        } // act as getter if no svg string is given


        if (svgOrFn == null || typeof svgOrFn === 'function') {
          // The default for exports is, that the outerNode is included
          outerHTML = outerHTML == null ? true : outerHTML; // write svgjs data to the dom

          this.writeDataToDom();
          var current = this; // An export modifier was passed

          if (svgOrFn != null) {
            current = adopt(current.node.cloneNode(true)); // If the user wants outerHTML we need to process this node, too

            if (outerHTML) {
              var result = svgOrFn(current);
              current = result || current; // The user does not want this node? Well, then he gets nothing

              if (result === false) return '';
            } // Deep loop through all children and apply modifier


            current.each(function () {
              var result = svgOrFn(this);

              var _this = result || this; // If modifier returns false, discard node


              if (result === false) {
                this.remove(); // If modifier returns new node, use it
              } else if (result && this !== _this) {
                this.replace(_this);
              }
            }, true);
          } // Return outer or inner content


          return outerHTML ? current.node.outerHTML : current.node.innerHTML;
        } // Act as setter if we got a string
        // The default for import is, that the current node is not replaced


        outerHTML = outerHTML == null ? false : outerHTML; // Create temporary holder

        well = globals.document.createElementNS(ns, 'svg');
        fragment = globals.document.createDocumentFragment(); // Dump raw svg

        well.innerHTML = svgOrFn; // Transplant nodes into the fragment

        for (len = well.children.length; len--;) {
          fragment.appendChild(well.firstElementChild);
        }

        var parent = this.parent(); // Add the whole fragment at once

        return outerHTML ? this.replace(fragment) && parent : this.add(fragment);
      }
    }, {
      key: "words",
      value: function words(text) {
        // This is faster than removing all children and adding a new one
        this.node.textContent = text;
        return this;
      } // write svgjs data to the dom

    }, {
      key: "writeDataToDom",
      value: function writeDataToDom() {
        // dump variables recursively
        this.each(function () {
          this.writeDataToDom();
        });
        return this;
      }
    }]);

    return Dom;
  }(EventTarget);

  extend(Dom, {
    attr: attr,
    find: find,
    findOne: findOne
  });
  register(Dom, 'Dom');

  var Element = /*#__PURE__*/function (_Dom) {
    _inherits(Element, _Dom);

    function Element(node, attrs) {
      var _this;

      _classCallCheck(this, Element);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(Element).call(this, node, attrs)); // initialize data object

      _this.dom = {}; // create circular reference

      _this.node.instance = _assertThisInitialized(_this);

      if (node.hasAttribute('svgjs:data')) {
        // pull svgjs data from the dom (getAttributeNS doesn't work in html5)
        _this.setData(JSON.parse(node.getAttribute('svgjs:data')) || {});
      }

      return _this;
    } // Move element by its center


    _createClass(Element, [{
      key: "center",
      value: function center(x, y) {
        return this.cx(x).cy(y);
      } // Move by center over x-axis

    }, {
      key: "cx",
      value: function cx(x) {
        return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2);
      } // Move by center over y-axis

    }, {
      key: "cy",
      value: function cy(y) {
        return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2);
      } // Get defs

    }, {
      key: "defs",
      value: function defs() {
        return this.root().defs();
      } // Relative move over x and y axes

    }, {
      key: "dmove",
      value: function dmove(x, y) {
        return this.dx(x).dy(y);
      } // Relative move over x axis

    }, {
      key: "dx",
      value: function dx() {
        var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        return this.x(new SVGNumber(x).plus(this.x()));
      } // Relative move over y axis

    }, {
      key: "dy",
      value: function dy() {
        var y = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        return this.y(new SVGNumber(y).plus(this.y()));
      } // Get parent document

    }, {
      key: "root",
      value: function root$1() {
        var p = this.parent(getClass(root));
        return p && p.root();
      }
    }, {
      key: "getEventHolder",
      value: function getEventHolder() {
        return this;
      } // Set height of element

    }, {
      key: "height",
      value: function height(_height) {
        return this.attr('height', _height);
      } // Checks whether the given point inside the bounding box of the element

    }, {
      key: "inside",
      value: function inside(x, y) {
        var box = this.bbox();
        return x > box.x && y > box.y && x < box.x + box.width && y < box.y + box.height;
      } // Move element to given x and y values

    }, {
      key: "move",
      value: function move(x, y) {
        return this.x(x).y(y);
      } // return array of all ancestors of given type up to the root svg

    }, {
      key: "parents",
      value: function parents() {
        var until = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : globals.document;
        until = makeInstance(until);
        var parents = new List();
        var parent = this;

        while ((parent = parent.parent()) && parent.node !== until.node && parent.node !== globals.document) {
          parents.push(parent);
        }

        return parents;
      } // Get referenced element form attribute value

    }, {
      key: "reference",
      value: function reference$1(attr) {
        attr = this.attr(attr);
        if (!attr) return null;
        var m = attr.match(reference);
        return m ? makeInstance(m[1]) : null;
      } // set given data to the elements data property

    }, {
      key: "setData",
      value: function setData(o) {
        this.dom = o;
        return this;
      } // Set element size to given width and height

    }, {
      key: "size",
      value: function size(width, height) {
        var p = proportionalSize(this, width, height);
        return this.width(new SVGNumber(p.width)).height(new SVGNumber(p.height));
      } // Set width of element

    }, {
      key: "width",
      value: function width(_width) {
        return this.attr('width', _width);
      } // write svgjs data to the dom

    }, {
      key: "writeDataToDom",
      value: function writeDataToDom() {
        // remove previously set data
        this.node.removeAttribute('svgjs:data');

        if (Object.keys(this.dom).length) {
          this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)); // see #428
        }

        return _get(_getPrototypeOf(Element.prototype), "writeDataToDom", this).call(this);
      } // Move over x-axis

    }, {
      key: "x",
      value: function x(_x) {
        return this.attr('x', _x);
      } // Move over y-axis

    }, {
      key: "y",
      value: function y(_y) {
        return this.attr('y', _y);
      }
    }]);

    return Element;
  }(Dom);

  extend(Element, {
    bbox: bbox,
    rbox: rbox,
    point: point,
    ctm: ctm,
    screenCTM: screenCTM
  });
  register(Element, 'Element');
  var sugar = {
    stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'],
    fill: ['color', 'opacity', 'rule'],
    prefix: function prefix(t, a) {
      return a === 'color' ? t : t + '-' + a;
    }
  } // Add sugar for fill and stroke
  ;
  ['fill', 'stroke'].forEach(function (m) {
    var extension = {};
    var i;

    extension[m] = function (o) {
      if (typeof o === 'undefined') {
        return this.attr(m);
      }

      if (typeof o === 'string' || o instanceof Color || Color.isRgb(o) || o instanceof Element) {
        this.attr(m, o);
      } else {
        // set all attributes from sugar.fill and sugar.stroke list
        for (i = sugar[m].length - 1; i >= 0; i--) {
          if (o[sugar[m][i]] != null) {
            this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]]);
          }
        }
      }

      return this;
    };

    registerMethods(['Element', 'Runner'], extension);
  });
  registerMethods(['Element', 'Runner'], {
    // Let the user set the matrix directly
    matrix: function matrix(mat, b, c, d, e, f) {
      // Act as a getter
      if (mat == null) {
        return new Matrix(this);
      } // Act as a setter, the user can pass a matrix or a set of numbers


      return this.attr('transform', new Matrix(mat, b, c, d, e, f));
    },
    // Map rotation to transform
    rotate: function rotate(angle, cx, cy) {
      return this.transform({
        rotate: angle,
        ox: cx,
        oy: cy
      }, true);
    },
    // Map skew to transform
    skew: function skew(x, y, cx, cy) {
      return arguments.length === 1 || arguments.length === 3 ? this.transform({
        skew: x,
        ox: y,
        oy: cx
      }, true) : this.transform({
        skew: [x, y],
        ox: cx,
        oy: cy
      }, true);
    },
    shear: function shear(lam, cx, cy) {
      return this.transform({
        shear: lam,
        ox: cx,
        oy: cy
      }, true);
    },
    // Map scale to transform
    scale: function scale(x, y, cx, cy) {
      return arguments.length === 1 || arguments.length === 3 ? this.transform({
        scale: x,
        ox: y,
        oy: cx
      }, true) : this.transform({
        scale: [x, y],
        ox: cx,
        oy: cy
      }, true);
    },
    // Map translate to transform
    translate: function translate(x, y) {
      return this.transform({
        translate: [x, y]
      }, true);
    },
    // Map relative translations to transform
    relative: function relative(x, y) {
      return this.transform({
        relative: [x, y]
      }, true);
    },
    // Map flip to transform
    flip: function flip(direction, around) {
      var directionString = typeof direction === 'string' ? direction : isFinite(direction) ? 'both' : 'both';
      var origin = direction === 'both' && isFinite(around) ? [around, around] : direction === 'x' ? [around, 0] : direction === 'y' ? [0, around] : isFinite(direction) ? [direction, direction] : [0, 0];
      return this.transform({
        flip: directionString,
        origin: origin
      }, true);
    },
    // Opacity
    opacity: function opacity(value) {
      return this.attr('opacity', value);
    }
  });
  registerMethods('radius', {
    // Add x and y radius
    radius: function radius(x, y) {
      var type = (this._element || this).type;
      return type === 'radialGradient' || type === 'radialGradient' ? this.attr('r', new SVGNumber(x)) : this.rx(x).ry(y == null ? x : y);
    }
  });
  registerMethods('Path', {
    // Get path length
    length: function length() {
      return this.node.getTotalLength();
    },
    // Get point at length
    pointAt: function pointAt(length) {
      return new Point(this.node.getPointAtLength(length));
    }
  });
  registerMethods(['Element', 'Runner'], {
    // Set font
    font: function font(a, v) {
      if (_typeof(a) === 'object') {
        for (v in a) {
          this.font(v, a[v]);
        }

        return this;
      }

      return a === 'leading' ? this.leading(v) : a === 'anchor' ? this.attr('text-anchor', v) : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style' ? this.attr('font-' + a, v) : this.attr(a, v);
    }
  });
  registerMethods('Text', {
    ax: function ax(x) {
      return this.attr('x', x);
    },
    ay: function ay(y) {
      return this.attr('y', y);
    },
    amove: function amove(x, y) {
      return this.ax(x).ay(y);
    }
  }); // Add events to elements

  var methods$1 = ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'mouseenter', 'mouseleave', 'touchstart', 'touchmove', 'touchleave', 'touchend', 'touchcancel'].reduce(function (last, event) {
    // add event to Element
    var fn = function fn(f) {
      if (f === null) {
        off(this, event);
      } else {
        on(this, event, f);
      }

      return this;
    };

    last[event] = fn;
    return last;
  }, {});
  registerMethods('Element', methods$1);
  var nativeReverse = [].reverse;
  var test$1 = [1, 2]; // `Array.prototype.reverse` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.reverse
  // fix for Safari 12.0 bug
  // https://bugs.webkit.org/show_bug.cgi?id=188794

  _export({
    target: 'Array',
    proto: true,
    forced: String(test$1) === String(test$1.reverse())
  }, {
    reverse: function reverse() {
      // eslint-disable-next-line no-self-assign
      if (isArray(this)) this.length = this.length;
      return nativeReverse.call(this);
    }
  }); // `Object.defineProperties` method
  // https://tc39.github.io/ecma262/#sec-object.defineproperties


  _export({
    target: 'Object',
    stat: true,
    forced: !descriptors,
    sham: !descriptors
  }, {
    defineProperties: objectDefineProperties
  }); // `Object.defineProperty` method
  // https://tc39.github.io/ecma262/#sec-object.defineproperty


  _export({
    target: 'Object',
    stat: true,
    forced: !descriptors,
    sham: !descriptors
  }, {
    defineProperty: objectDefineProperty.f
  });

  var nativeGetOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
  var FAILS_ON_PRIMITIVES$2 = fails(function () {
    nativeGetOwnPropertyDescriptor$2(1);
  });
  var FORCED$3 = !descriptors || FAILS_ON_PRIMITIVES$2; // `Object.getOwnPropertyDescriptor` method
  // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor

  _export({
    target: 'Object',
    stat: true,
    forced: FORCED$3,
    sham: !descriptors
  }, {
    getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
      return nativeGetOwnPropertyDescriptor$2(toIndexedObject(it), key);
    }
  }); // `Object.getOwnPropertyDescriptors` method
  // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors


  _export({
    target: 'Object',
    stat: true,
    sham: !descriptors
  }, {
    getOwnPropertyDescriptors: function getOwnPropertyDescriptors(object) {
      var O = toIndexedObject(object);
      var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
      var keys = ownKeys(O);
      var result = {};
      var index = 0;
      var key, descriptor;

      while (keys.length > index) {
        descriptor = getOwnPropertyDescriptor(O, key = keys[index++]);
        if (descriptor !== undefined) createProperty(result, key, descriptor);
      }

      return result;
    }
  });

  function _defineProperty(obj, key, value) {
    if (key in obj) {
      Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
      });
    } else {
      obj[key] = value;
    }

    return obj;
  }

  function ownKeys$1(object, enumerableOnly) {
    var keys = Object.keys(object);

    if (Object.getOwnPropertySymbols) {
      var symbols = Object.getOwnPropertySymbols(object);
      if (enumerableOnly) symbols = symbols.filter(function (sym) {
        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
      });
      keys.push.apply(keys, symbols);
    }

    return keys;
  }

  function _objectSpread(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i] != null ? arguments[i] : {};

      if (i % 2) {
        ownKeys$1(source, true).forEach(function (key) {
          _defineProperty(target, key, source[key]);
        });
      } else if (Object.getOwnPropertyDescriptors) {
        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
      } else {
        ownKeys$1(source).forEach(function (key) {
          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
        });
      }
    }

    return target;
  }

  function untransform() {
    return this.attr('transform', null);
  } // merge the whole transformation chain into one matrix and returns it


  function matrixify() {
    var matrix = (this.attr('transform') || ''). // split transformations
    split(transforms).slice(0, -1).map(function (str) {
      // generate key => value pairs
      var kv = str.trim().split('(');
      return [kv[0], kv[1].split(delimiter).map(function (str) {
        return parseFloat(str);
      })];
    }).reverse() // merge every transformation into one matrix
    .reduce(function (matrix, transform) {
      if (transform[0] === 'matrix') {
        return matrix.lmultiply(Matrix.fromArray(transform[1]));
      }

      return matrix[transform[0]].apply(matrix, transform[1]);
    }, new Matrix());
    return matrix;
  } // add an element to another parent without changing the visual representation on the screen


  function toParent(parent) {
    if (this === parent) return this;
    var ctm = this.screenCTM();
    var pCtm = parent.screenCTM().inverse();
    this.addTo(parent).untransform().transform(pCtm.multiply(ctm));
    return this;
  } // same as above with parent equals root-svg


  function toRoot() {
    return this.toParent(this.root());
  } // Add transformations


  function transform(o, relative) {
    // Act as a getter if no object was passed
    if (o == null || typeof o === 'string') {
      var decomposed = new Matrix(this).decompose();
      return o == null ? decomposed : decomposed[o];
    }

    if (!Matrix.isMatrixLike(o)) {
      // Set the origin according to the defined transform
      o = _objectSpread({}, o, {
        origin: getOrigin(o, this)
      });
    } // The user can pass a boolean, an Element or an Matrix or nothing


    var cleanRelative = relative === true ? this : relative || false;
    var result = new Matrix(cleanRelative).transform(o);
    return this.attr('transform', result);
  }

  registerMethods('Element', {
    untransform: untransform,
    matrixify: matrixify,
    toParent: toParent,
    toRoot: toRoot,
    transform: transform
  });

  function rx(rx) {
    return this.attr('rx', rx);
  } // Radius y value


  function ry(ry) {
    return this.attr('ry', ry);
  } // Move over x-axis


  function x(x) {
    return x == null ? this.cx() - this.rx() : this.cx(x + this.rx());
  } // Move over y-axis


  function y(y) {
    return y == null ? this.cy() - this.ry() : this.cy(y + this.ry());
  } // Move by center over x-axis


  function cx(x) {
    return x == null ? this.attr('cx') : this.attr('cx', x);
  } // Move by center over y-axis


  function cy(y) {
    return y == null ? this.attr('cy') : this.attr('cy', y);
  } // Set width of element


  function width(width) {
    return width == null ? this.rx() * 2 : this.rx(new SVGNumber(width).divide(2));
  } // Set height of element


  function height(height) {
    return height == null ? this.ry() * 2 : this.ry(new SVGNumber(height).divide(2));
  }

  var circled = {
    __proto__: null,
    rx: rx,
    ry: ry,
    x: x,
    y: y,
    cx: cx,
    cy: cy,
    width: width,
    height: height
  };

  var Shape = /*#__PURE__*/function (_Element) {
    _inherits(Shape, _Element);

    function Shape() {
      _classCallCheck(this, Shape);

      return _possibleConstructorReturn(this, _getPrototypeOf(Shape).apply(this, arguments));
    }

    return Shape;
  }(Element);

  register(Shape, 'Shape');

  var Circle = /*#__PURE__*/function (_Shape) {
    _inherits(Circle, _Shape);

    function Circle(node) {
      _classCallCheck(this, Circle);

      return _possibleConstructorReturn(this, _getPrototypeOf(Circle).call(this, nodeOrNew('circle', node), node));
    }

    _createClass(Circle, [{
      key: "radius",
      value: function radius(r) {
        return this.attr('r', r);
      } // Radius x value

    }, {
      key: "rx",
      value: function rx(_rx) {
        return this.attr('r', _rx);
      } // Alias radius x value

    }, {
      key: "ry",
      value: function ry(_ry) {
        return this.rx(_ry);
      }
    }, {
      key: "size",
      value: function size(_size) {
        return this.radius(new SVGNumber(_size).divide(2));
      }
    }]);

    return Circle;
  }(Shape);

  extend(Circle, {
    x: x,
    y: y,
    cx: cx,
    cy: cy,
    width: width,
    height: height
  });
  registerMethods({
    Container: {
      // Create circle element
      circle: wrapWithAttrCheck(function (size) {
        return this.put(new Circle()).size(size).move(0, 0);
      })
    }
  });
  register(Circle, 'Circle');

  var Container = /*#__PURE__*/function (_Element) {
    _inherits(Container, _Element);

    function Container() {
      _classCallCheck(this, Container);

      return _possibleConstructorReturn(this, _getPrototypeOf(Container).apply(this, arguments));
    }

    _createClass(Container, [{
      key: "flatten",
      value: function flatten(parent) {
        this.each(function () {
          if (this instanceof Container) return this.flatten(parent).ungroup(parent);
          return this.toParent(parent);
        }); // we need this so that the root does not get removed

        this.node.firstElementChild || this.remove();
        return this;
      }
    }, {
      key: "ungroup",
      value: function ungroup(parent) {
        parent = parent || this.parent();
        this.each(function () {
          return this.toParent(parent);
        });
        this.remove();
        return this;
      }
    }]);

    return Container;
  }(Element);

  register(Container, 'Container');

  var Defs = /*#__PURE__*/function (_Container) {
    _inherits(Defs, _Container);

    function Defs(node) {
      _classCallCheck(this, Defs);

      return _possibleConstructorReturn(this, _getPrototypeOf(Defs).call(this, nodeOrNew('defs', node), node));
    }

    _createClass(Defs, [{
      key: "flatten",
      value: function flatten() {
        return this;
      }
    }, {
      key: "ungroup",
      value: function ungroup() {
        return this;
      }
    }]);

    return Defs;
  }(Container);

  register(Defs, 'Defs');

  var Ellipse = /*#__PURE__*/function (_Shape) {
    _inherits(Ellipse, _Shape);

    function Ellipse(node) {
      _classCallCheck(this, Ellipse);

      return _possibleConstructorReturn(this, _getPrototypeOf(Ellipse).call(this, nodeOrNew('ellipse', node), node));
    }

    _createClass(Ellipse, [{
      key: "size",
      value: function size(width, height) {
        var p = proportionalSize(this, width, height);
        return this.rx(new SVGNumber(p.width).divide(2)).ry(new SVGNumber(p.height).divide(2));
      }
    }]);

    return Ellipse;
  }(Shape);

  extend(Ellipse, circled);
  registerMethods('Container', {
    // Create an ellipse
    ellipse: wrapWithAttrCheck(function () {
      var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
      var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : width;
      return this.put(new Ellipse()).size(width, height).move(0, 0);
    })
  });
  register(Ellipse, 'Ellipse');

  var Stop = /*#__PURE__*/function (_Element) {
    _inherits(Stop, _Element);

    function Stop(node) {
      _classCallCheck(this, Stop);

      return _possibleConstructorReturn(this, _getPrototypeOf(Stop).call(this, nodeOrNew('stop', node), node));
    } // add color stops


    _createClass(Stop, [{
      key: "update",
      value: function update(o) {
        if (typeof o === 'number' || o instanceof SVGNumber) {
          o = {
            offset: arguments[0],
            color: arguments[1],
            opacity: arguments[2]
          };
        } // set attributes


        if (o.opacity != null) this.attr('stop-opacity', o.opacity);
        if (o.color != null) this.attr('stop-color', o.color);
        if (o.offset != null) this.attr('offset', new SVGNumber(o.offset));
        return this;
      }
    }]);

    return Stop;
  }(Element);

  register(Stop, 'Stop');

  function from(x, y) {
    return (this._element || this).type === 'radialGradient' ? this.attr({
      fx: new SVGNumber(x),
      fy: new SVGNumber(y)
    }) : this.attr({
      x1: new SVGNumber(x),
      y1: new SVGNumber(y)
    });
  }

  function to(x, y) {
    return (this._element || this).type === 'radialGradient' ? this.attr({
      cx: new SVGNumber(x),
      cy: new SVGNumber(y)
    }) : this.attr({
      x2: new SVGNumber(x),
      y2: new SVGNumber(y)
    });
  }

  var gradiented = {
    __proto__: null,
    from: from,
    to: to
  };

  var Gradient = /*#__PURE__*/function (_Container) {
    _inherits(Gradient, _Container);

    function Gradient(type, attrs) {
      _classCallCheck(this, Gradient);

      return _possibleConstructorReturn(this, _getPrototypeOf(Gradient).call(this, nodeOrNew(type + 'Gradient', typeof type === 'string' ? null : type), attrs));
    } // Add a color stop


    _createClass(Gradient, [{
      key: "stop",
      value: function stop(offset, color, opacity) {
        return this.put(new Stop()).update(offset, color, opacity);
      } // Update gradient

    }, {
      key: "update",
      value: function update(block) {
        // remove all stops
        this.clear(); // invoke passed block

        if (typeof block === 'function') {
          block.call(this, this);
        }

        return this;
      } // Return the fill id

    }, {
      key: "url",
      value: function url() {
        return 'url(#' + this.id() + ')';
      } // Alias string convertion to fill

    }, {
      key: "toString",
      value: function toString() {
        return this.url();
      } // custom attr to handle transform

    }, {
      key: "attr",
      value: function attr(a, b, c) {
        if (a === 'transform') a = 'gradientTransform';
        return _get(_getPrototypeOf(Gradient.prototype), "attr", this).call(this, a, b, c);
      }
    }, {
      key: "targets",
      value: function targets() {
        return baseFind('svg [fill*="' + this.id() + '"]');
      }
    }, {
      key: "bbox",
      value: function bbox() {
        return new Box();
      }
    }]);

    return Gradient;
  }(Container);

  extend(Gradient, gradiented);
  registerMethods({
    Container: {
      // Create gradient element in defs
      gradient: wrapWithAttrCheck(function (type, block) {
        return this.defs().gradient(type, block);
      })
    },
    // define gradient
    Defs: {
      gradient: wrapWithAttrCheck(function (type, block) {
        return this.put(new Gradient(type)).update(block);
      })
    }
  });
  register(Gradient, 'Gradient');

  var Pattern = /*#__PURE__*/function (_Container) {
    _inherits(Pattern, _Container); // Initialize node


    function Pattern(node) {
      _classCallCheck(this, Pattern);

      return _possibleConstructorReturn(this, _getPrototypeOf(Pattern).call(this, nodeOrNew('pattern', node), node));
    } // Return the fill id


    _createClass(Pattern, [{
      key: "url",
      value: function url() {
        return 'url(#' + this.id() + ')';
      } // Update pattern by rebuilding

    }, {
      key: "update",
      value: function update(block) {
        // remove content
        this.clear(); // invoke passed block

        if (typeof block === 'function') {
          block.call(this, this);
        }

        return this;
      } // Alias string convertion to fill

    }, {
      key: "toString",
      value: function toString() {
        return this.url();
      } // custom attr to handle transform

    }, {
      key: "attr",
      value: function attr(a, b, c) {
        if (a === 'transform') a = 'patternTransform';
        return _get(_getPrototypeOf(Pattern.prototype), "attr", this).call(this, a, b, c);
      }
    }, {
      key: "targets",
      value: function targets() {
        return baseFind('svg [fill*="' + this.id() + '"]');
      }
    }, {
      key: "bbox",
      value: function bbox() {
        return new Box();
      }
    }]);

    return Pattern;
  }(Container);

  registerMethods({
    Container: {
      // Create pattern element in defs
      pattern: function pattern() {
        var _this$defs;

        return (_this$defs = this.defs()).pattern.apply(_this$defs, arguments);
      }
    },
    Defs: {
      pattern: wrapWithAttrCheck(function (width, height, block) {
        return this.put(new Pattern()).update(block).attr({
          x: 0,
          y: 0,
          width: width,
          height: height,
          patternUnits: 'userSpaceOnUse'
        });
      })
    }
  });
  register(Pattern, 'Pattern');

  var Image = /*#__PURE__*/function (_Shape) {
    _inherits(Image, _Shape);

    function Image(node) {
      _classCallCheck(this, Image);

      return _possibleConstructorReturn(this, _getPrototypeOf(Image).call(this, nodeOrNew('image', node), node));
    } // (re)load image


    _createClass(Image, [{
      key: "load",
      value: function load(url, callback) {
        if (!url) return this;
        var img = new globals.window.Image();
        on(img, 'load', function (e) {
          var p = this.parent(Pattern); // ensure image size

          if (this.width() === 0 && this.height() === 0) {
            this.size(img.width, img.height);
          }

          if (p instanceof Pattern) {
            // ensure pattern size if not set
            if (p.width() === 0 && p.height() === 0) {
              p.size(this.width(), this.height());
            }
          }

          if (typeof callback === 'function') {
            callback.call(this, e);
          }
        }, this);
        on(img, 'load error', function () {
          // dont forget to unbind memory leaking events
          off(img);
        });
        return this.attr('href', img.src = url, xlink);
      }
    }]);

    return Image;
  }(Shape);

  registerAttrHook(function (attr, val, _this) {
    // convert image fill and stroke to patterns
    if (attr === 'fill' || attr === 'stroke') {
      if (isImage.test(val)) {
        val = _this.root().defs().image(val);
      }
    }

    if (val instanceof Image) {
      val = _this.root().defs().pattern(0, 0, function (pattern) {
        pattern.add(val);
      });
    }

    return val;
  });
  registerMethods({
    Container: {
      // create image element, load image and set its size
      image: wrapWithAttrCheck(function (source, callback) {
        return this.put(new Image()).size(0, 0).load(source, callback);
      })
    }
  });
  register(Image, 'Image');
  var PointArray = subClassArray('PointArray', SVGArray);
  extend(PointArray, {
    // Convert array to string
    toString: function toString() {
      // convert to a poly point string
      for (var i = 0, il = this.length, array = []; i < il; i++) {
        array.push(this[i].join(','));
      }

      return array.join(' ');
    },
    // Convert array to line object
    toLine: function toLine() {
      return {
        x1: this[0][0],
        y1: this[0][1],
        x2: this[1][0],
        y2: this[1][1]
      };
    },
    // Get morphed array at given position
    at: function at(pos) {
      // make sure a destination is defined
      if (!this.destination) return this; // generate morphed point string

      for (var i = 0, il = this.length, array = []; i < il; i++) {
        array.push([this[i][0] + (this.destination[i][0] - this[i][0]) * pos, this[i][1] + (this.destination[i][1] - this[i][1]) * pos]);
      }

      return new PointArray(array);
    },
    // Parse point string and flat array
    parse: function parse() {
      var array = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [[0, 0]];
      var points = []; // if it is an array

      if (array instanceof Array) {
        // and it is not flat, there is no need to parse it
        if (array[0] instanceof Array) {
          return array;
        }
      } else {
        // Else, it is considered as a string
        // parse points
        array = array.trim().split(delimiter).map(parseFloat);
      } // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
      // Odd number of coordinates is an error. In such cases, drop the last odd coordinate.


      if (array.length % 2 !== 0) array.pop(); // wrap points in two-tuples

      for (var i = 0, len = array.length; i < len; i = i + 2) {
        points.push([array[i], array[i + 1]]);
      }

      return points;
    },
    // transform points with matrix (similar to Point.transform)
    transform: function transform(m) {
      var points = [];

      for (var i = 0; i < this.length; i++) {
        var point = this[i]; // Perform the matrix multiplication

        points.push([m.a * point[0] + m.c * point[1] + m.e, m.b * point[0] + m.d * point[1] + m.f]);
      } // Return the required point


      return new PointArray(points);
    },
    // Move point string
    move: function move(x, y) {
      var box = this.bbox(); // get relative offset

      x -= box.x;
      y -= box.y; // move every point

      if (!isNaN(x) && !isNaN(y)) {
        for (var i = this.length - 1; i >= 0; i--) {
          this[i] = [this[i][0] + x, this[i][1] + y];
        }
      }

      return this;
    },
    // Resize poly string
    size: function size(width, height) {
      var i;
      var box = this.bbox(); // recalculate position of all points according to new size

      for (i = this.length - 1; i >= 0; i--) {
        if (box.width) this[i][0] = (this[i][0] - box.x) * width / box.width + box.x;
        if (box.height) this[i][1] = (this[i][1] - box.y) * height / box.height + box.y;
      }

      return this;
    },
    // Get bounding box of points
    bbox: function bbox() {
      var maxX = -Infinity;
      var maxY = -Infinity;
      var minX = Infinity;
      var minY = Infinity;
      this.forEach(function (el) {
        maxX = Math.max(el[0], maxX);
        maxY = Math.max(el[1], maxY);
        minX = Math.min(el[0], minX);
        minY = Math.min(el[1], minY);
      });
      return {
        x: minX,
        y: minY,
        width: maxX - minX,
        height: maxY - minY
      };
    }
  });
  var MorphArray = PointArray; // Move by left top corner over x-axis

  function x$1(x) {
    return x == null ? this.bbox().x : this.move(x, this.bbox().y);
  } // Move by left top corner over y-axis


  function y$1(y) {
    return y == null ? this.bbox().y : this.move(this.bbox().x, y);
  } // Set width of element


  function width$1(width) {
    var b = this.bbox();
    return width == null ? b.width : this.size(width, b.height);
  } // Set height of element


  function height$1(height) {
    var b = this.bbox();
    return height == null ? b.height : this.size(b.width, height);
  }

  var pointed = {
    __proto__: null,
    MorphArray: MorphArray,
    x: x$1,
    y: y$1,
    width: width$1,
    height: height$1
  };

  var Line = /*#__PURE__*/function (_Shape) {
    _inherits(Line, _Shape); // Initialize node


    function Line(node) {
      _classCallCheck(this, Line);

      return _possibleConstructorReturn(this, _getPrototypeOf(Line).call(this, nodeOrNew('line', node), node));
    } // Get array


    _createClass(Line, [{
      key: "array",
      value: function array() {
        return new PointArray([[this.attr('x1'), this.attr('y1')], [this.attr('x2'), this.attr('y2')]]);
      } // Overwrite native plot() method

    }, {
      key: "plot",
      value: function plot(x1, y1, x2, y2) {
        if (x1 == null) {
          return this.array();
        } else if (typeof y1 !== 'undefined') {
          x1 = {
            x1: x1,
            y1: y1,
            x2: x2,
            y2: y2
          };
        } else {
          x1 = new PointArray(x1).toLine();
        }

        return this.attr(x1);
      } // Move by left top corner

    }, {
      key: "move",
      value: function move(x, y) {
        return this.attr(this.array().move(x, y).toLine());
      } // Set element size to given width and height

    }, {
      key: "size",
      value: function size(width, height) {
        var p = proportionalSize(this, width, height);
        return this.attr(this.array().size(p.width, p.height).toLine());
      }
    }]);

    return Line;
  }(Shape);

  extend(Line, pointed);
  registerMethods({
    Container: {
      // Create a line element
      line: wrapWithAttrCheck(function () {
        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        } // make sure plot is called as a setter
        // x1 is not necessarily a number, it can also be an array, a string and a PointArray


        return Line.prototype.plot.apply(this.put(new Line()), args[0] != null ? args : [0, 0, 0, 0]);
      })
    }
  });
  register(Line, 'Line');

  var Marker = /*#__PURE__*/function (_Container) {
    _inherits(Marker, _Container); // Initialize node


    function Marker(node) {
      _classCallCheck(this, Marker);

      return _possibleConstructorReturn(this, _getPrototypeOf(Marker).call(this, nodeOrNew('marker', node), node));
    } // Set width of element


    _createClass(Marker, [{
      key: "width",
      value: function width(_width) {
        return this.attr('markerWidth', _width);
      } // Set height of element

    }, {
      key: "height",
      value: function height(_height) {
        return this.attr('markerHeight', _height);
      } // Set marker refX and refY

    }, {
      key: "ref",
      value: function ref(x, y) {
        return this.attr('refX', x).attr('refY', y);
      } // Update marker

    }, {
      key: "update",
      value: function update(block) {
        // remove all content
        this.clear(); // invoke passed block

        if (typeof block === 'function') {
          block.call(this, this);
        }

        return this;
      } // Return the fill id

    }, {
      key: "toString",
      value: function toString() {
        return 'url(#' + this.id() + ')';
      }
    }]);

    return Marker;
  }(Container);

  registerMethods({
    Container: {
      marker: function marker() {
        var _this$defs; // Create marker element in defs


        return (_this$defs = this.defs()).marker.apply(_this$defs, arguments);
      }
    },
    Defs: {
      // Create marker
      marker: wrapWithAttrCheck(function (width, height, block) {
        // Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto
        return this.put(new Marker()).size(width, height).ref(width / 2, height / 2).viewbox(0, 0, width, height).attr('orient', 'auto').update(block);
      })
    },
    marker: {
      // Create and attach markers
      marker: function marker(_marker, width, height, block) {
        var attr = ['marker']; // Build attribute name

        if (_marker !== 'all') attr.push(_marker);
        attr = attr.join('-'); // Set marker attribute

        _marker = arguments[1] instanceof Marker ? arguments[1] : this.defs().marker(width, height, block);
        return this.attr(attr, _marker);
      }
    }
  });
  register(Marker, 'Marker');
  var nativeSort = [].sort;
  var test$2 = [1, 2, 3]; // IE8-

  var FAILS_ON_UNDEFINED = fails(function () {
    test$2.sort(undefined);
  }); // V8 bug

  var FAILS_ON_NULL = fails(function () {
    test$2.sort(null);
  }); // Old WebKit

  var SLOPPY_METHOD$2 = sloppyArrayMethod('sort');
  var FORCED$4 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || SLOPPY_METHOD$2; // `Array.prototype.sort` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.sort

  _export({
    target: 'Array',
    proto: true,
    forced: FORCED$4
  }, {
    sort: function sort(comparefn) {
      return comparefn === undefined ? nativeSort.call(toObject(this)) : nativeSort.call(toObject(this), aFunction$1(comparefn));
    }
  });
  /***
  Base Class
  ==========
  The base stepper class that will be
  ***/


  function makeSetterGetter(k, f) {
    return function (v) {
      if (v == null) return this[v];
      this[k] = v;
      if (f) f.call(this);
      return this;
    };
  }

  var easing = {
    '-': function _(pos) {
      return pos;
    },
    '<>': function _(pos) {
      return -Math.cos(pos * Math.PI) / 2 + 0.5;
    },
    '>': function _(pos) {
      return Math.sin(pos * Math.PI / 2);
    },
    '<': function _(pos) {
      return -Math.cos(pos * Math.PI / 2) + 1;
    },
    bezier: function bezier(x1, y1, x2, y2) {
      // see https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo
      return function (t) {
        if (t < 0) {
          if (x1 > 0) {
            return y1 / x1 * t;
          } else if (x2 > 0) {
            return y2 / x2 * t;
          } else {
            return 0;
          }
        } else if (t > 1) {
          if (x2 < 1) {
            return (1 - y2) / (1 - x2) * t + (y2 - x2) / (1 - x2);
          } else if (x1 < 1) {
            return (1 - y1) / (1 - x1) * t + (y1 - x1) / (1 - x1);
          } else {
            return 1;
          }
        } else {
          return 3 * t * Math.pow(1 - t, 2) * y1 + 3 * Math.pow(t, 2) * (1 - t) * y2 + Math.pow(t, 3);
        }
      };
    },
    // see https://www.w3.org/TR/css-easing-1/#step-timing-function-algo
    steps: function steps(_steps) {
      var stepPosition = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'end'; // deal with "jump-" prefix

      stepPosition = stepPosition.split('-').reverse()[0];
      var jumps = _steps;

      if (stepPosition === 'none') {
        --jumps;
      } else if (stepPosition === 'both') {
        ++jumps;
      } // The beforeFlag is essentially useless


      return function (t) {
        var beforeFlag = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; // Step is called currentStep in referenced url

        var step = Math.floor(t * _steps);
        var jumping = t * step % 1 === 0;

        if (stepPosition === 'start' || stepPosition === 'both') {
          ++step;
        }

        if (beforeFlag && jumping) {
          --step;
        }

        if (t >= 0 && step < 0) {
          step = 0;
        }

        if (t <= 1 && step > jumps) {
          step = jumps;
        }

        return step / jumps;
      };
    }
  };

  var Stepper = /*#__PURE__*/function () {
    function Stepper() {
      _classCallCheck(this, Stepper);
    }

    _createClass(Stepper, [{
      key: "done",
      value: function done() {
        return false;
      }
    }]);

    return Stepper;
  }();
  /***
  Easing Functions
  ================
  ***/


  var Ease = /*#__PURE__*/function (_Stepper) {
    _inherits(Ease, _Stepper);

    function Ease(fn) {
      var _this;

      _classCallCheck(this, Ease);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(Ease).call(this));
      _this.ease = easing[fn || timeline.ease] || fn;
      return _this;
    }

    _createClass(Ease, [{
      key: "step",
      value: function step(from, to, pos) {
        if (typeof from !== 'number') {
          return pos < 1 ? from : to;
        }

        return from + (to - from) * this.ease(pos);
      }
    }]);

    return Ease;
  }(Stepper);
  /***
  Controller Types
  ================
  ***/


  var Controller = /*#__PURE__*/function (_Stepper2) {
    _inherits(Controller, _Stepper2);

    function Controller(fn) {
      var _this2;

      _classCallCheck(this, Controller);

      _this2 = _possibleConstructorReturn(this, _getPrototypeOf(Controller).call(this));
      _this2.stepper = fn;
      return _this2;
    }

    _createClass(Controller, [{
      key: "step",
      value: function step(current, target, dt, c) {
        return this.stepper(current, target, dt, c);
      }
    }, {
      key: "done",
      value: function done(c) {
        return c.done;
      }
    }]);

    return Controller;
  }(Stepper);

  function recalculate() {
    // Apply the default parameters
    var duration = (this._duration || 500) / 1000;
    var overshoot = this._overshoot || 0; // Calculate the PID natural response

    var eps = 1e-10;
    var pi = Math.PI;
    var os = Math.log(overshoot / 100 + eps);
    var zeta = -os / Math.sqrt(pi * pi + os * os);
    var wn = 3.9 / (zeta * duration); // Calculate the Spring values

    this.d = 2 * zeta * wn;
    this.k = wn * wn;
  }

  var Spring = /*#__PURE__*/function (_Controller) {
    _inherits(Spring, _Controller);

    function Spring(duration, overshoot) {
      var _this3;

      _classCallCheck(this, Spring);

      _this3 = _possibleConstructorReturn(this, _getPrototypeOf(Spring).call(this));

      _this3.duration(duration || 500).overshoot(overshoot || 0);

      return _this3;
    }

    _createClass(Spring, [{
      key: "step",
      value: function step(current, target, dt, c) {
        if (typeof current === 'string') return current;
        c.done = dt === Infinity;
        if (dt === Infinity) return target;
        if (dt === 0) return current;
        if (dt > 100) dt = 16;
        dt /= 1000; // Get the previous velocity

        var velocity = c.velocity || 0; // Apply the control to get the new position and store it

        var acceleration = -this.d * velocity - this.k * (current - target);
        var newPosition = current + velocity * dt + acceleration * dt * dt / 2; // Store the velocity

        c.velocity = velocity + acceleration * dt; // Figure out if we have converged, and if so, pass the value

        c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002;
        return c.done ? target : newPosition;
      }
    }]);

    return Spring;
  }(Controller);

  extend(Spring, {
    duration: makeSetterGetter('_duration', recalculate),
    overshoot: makeSetterGetter('_overshoot', recalculate)
  });

  var PID = /*#__PURE__*/function (_Controller2) {
    _inherits(PID, _Controller2);

    function PID(p, i, d, windup) {
      var _this4;

      _classCallCheck(this, PID);

      _this4 = _possibleConstructorReturn(this, _getPrototypeOf(PID).call(this));
      p = p == null ? 0.1 : p;
      i = i == null ? 0.01 : i;
      d = d == null ? 0 : d;
      windup = windup == null ? 1000 : windup;

      _this4.p(p).i(i).d(d).windup(windup);

      return _this4;
    }

    _createClass(PID, [{
      key: "step",
      value: function step(current, target, dt, c) {
        if (typeof current === 'string') return current;
        c.done = dt === Infinity;
        if (dt === Infinity) return target;
        if (dt === 0) return current;
        var p = target - current;
        var i = (c.integral || 0) + p * dt;
        var d = (p - (c.error || 0)) / dt;
        var windup = this.windup; // antiwindup

        if (windup !== false) {
          i = Math.max(-windup, Math.min(i, windup));
        }

        c.error = p;
        c.integral = i;
        c.done = Math.abs(p) < 0.001;
        return c.done ? target : current + (this.P * p + this.I * i + this.D * d);
      }
    }]);

    return PID;
  }(Controller);

  extend(PID, {
    windup: makeSetterGetter('windup'),
    p: makeSetterGetter('P'),
    i: makeSetterGetter('I'),
    d: makeSetterGetter('D')
  });
  var PathArray = subClassArray('PathArray', SVGArray);

  function pathRegReplace(a, b, c, d) {
    return c + d.replace(dots, ' .');
  }

  function arrayToString(a) {
    for (var i = 0, il = a.length, s = ''; i < il; i++) {
      s += a[i][0];

      if (a[i][1] != null) {
        s += a[i][1];

        if (a[i][2] != null) {
          s += ' ';
          s += a[i][2];

          if (a[i][3] != null) {
            s += ' ';
            s += a[i][3];
            s += ' ';
            s += a[i][4];

            if (a[i][5] != null) {
              s += ' ';
              s += a[i][5];
              s += ' ';
              s += a[i][6];

              if (a[i][7] != null) {
                s += ' ';
                s += a[i][7];
              }
            }
          }
        }
      }
    }

    return s + ' ';
  }

  var pathHandlers = {
    M: function M(c, p, p0) {
      p.x = p0.x = c[0];
      p.y = p0.y = c[1];
      return ['M', p.x, p.y];
    },
    L: function L(c, p) {
      p.x = c[0];
      p.y = c[1];
      return ['L', c[0], c[1]];
    },
    H: function H(c, p) {
      p.x = c[0];
      return ['H', c[0]];
    },
    V: function V(c, p) {
      p.y = c[0];
      return ['V', c[0]];
    },
    C: function C(c, p) {
      p.x = c[4];
      p.y = c[5];
      return ['C', c[0], c[1], c[2], c[3], c[4], c[5]];
    },
    S: function S(c, p) {
      p.x = c[2];
      p.y = c[3];
      return ['S', c[0], c[1], c[2], c[3]];
    },
    Q: function Q(c, p) {
      p.x = c[2];
      p.y = c[3];
      return ['Q', c[0], c[1], c[2], c[3]];
    },
    T: function T(c, p) {
      p.x = c[0];
      p.y = c[1];
      return ['T', c[0], c[1]];
    },
    Z: function Z(c, p, p0) {
      p.x = p0.x;
      p.y = p0.y;
      return ['Z'];
    },
    A: function A(c, p) {
      p.x = c[5];
      p.y = c[6];
      return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]];
    }
  };
  var mlhvqtcsaz = 'mlhvqtcsaz'.split('');

  for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
    pathHandlers[mlhvqtcsaz[i]] = function (i) {
      return function (c, p, p0) {
        if (i === 'H') c[0] = c[0] + p.x;else if (i === 'V') c[0] = c[0] + p.y;else if (i === 'A') {
          c[5] = c[5] + p.x;
          c[6] = c[6] + p.y;
        } else {
          for (var j = 0, jl = c.length; j < jl; ++j) {
            c[j] = c[j] + (j % 2 ? p.y : p.x);
          }
        }
        return pathHandlers[i](c, p, p0);
      };
    }(mlhvqtcsaz[i].toUpperCase());
  }

  extend(PathArray, {
    // Convert array to string
    toString: function toString() {
      return arrayToString(this);
    },
    // Move path string
    move: function move(x, y) {
      // get bounding box of current situation
      var box = this.bbox(); // get relative offset

      x -= box.x;
      y -= box.y;

      if (!isNaN(x) && !isNaN(y)) {
        // move every point
        for (var l, i = this.length - 1; i >= 0; i--) {
          l = this[i][0];

          if (l === 'M' || l === 'L' || l === 'T') {
            this[i][1] += x;
            this[i][2] += y;
          } else if (l === 'H') {
            this[i][1] += x;
          } else if (l === 'V') {
            this[i][1] += y;
          } else if (l === 'C' || l === 'S' || l === 'Q') {
            this[i][1] += x;
            this[i][2] += y;
            this[i][3] += x;
            this[i][4] += y;

            if (l === 'C') {
              this[i][5] += x;
              this[i][6] += y;
            }
          } else if (l === 'A') {
            this[i][6] += x;
            this[i][7] += y;
          }
        }
      }

      return this;
    },
    // Resize path string
    size: function size(width, height) {
      // get bounding box of current situation
      var box = this.bbox();
      var i, l; // If the box width or height is 0 then we ignore
      // transformations on the respective axis

      box.width = box.width === 0 ? 1 : box.width;
      box.height = box.height === 0 ? 1 : box.height; // recalculate position of all points according to new size

      for (i = this.length - 1; i >= 0; i--) {
        l = this[i][0];

        if (l === 'M' || l === 'L' || l === 'T') {
          this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
          this[i][2] = (this[i][2] - box.y) * height / box.height + box.y;
        } else if (l === 'H') {
          this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
        } else if (l === 'V') {
          this[i][1] = (this[i][1] - box.y) * height / box.height + box.y;
        } else if (l === 'C' || l === 'S' || l === 'Q') {
          this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
          this[i][2] = (this[i][2] - box.y) * height / box.height + box.y;
          this[i][3] = (this[i][3] - box.x) * width / box.width + box.x;
          this[i][4] = (this[i][4] - box.y) * height / box.height + box.y;

          if (l === 'C') {
            this[i][5] = (this[i][5] - box.x) * width / box.width + box.x;
            this[i][6] = (this[i][6] - box.y) * height / box.height + box.y;
          }
        } else if (l === 'A') {
          // resize radii
          this[i][1] = this[i][1] * width / box.width;
          this[i][2] = this[i][2] * height / box.height; // move position values

          this[i][6] = (this[i][6] - box.x) * width / box.width + box.x;
          this[i][7] = (this[i][7] - box.y) * height / box.height + box.y;
        }
      }

      return this;
    },
    // Test if the passed path array use the same path data commands as this path array
    equalCommands: function equalCommands(pathArray) {
      var i, il, equalCommands;
      pathArray = new PathArray(pathArray);
      equalCommands = this.length === pathArray.length;

      for (i = 0, il = this.length; equalCommands && i < il; i++) {
        equalCommands = this[i][0] === pathArray[i][0];
      }

      return equalCommands;
    },
    // Make path array morphable
    morph: function morph(pathArray) {
      pathArray = new PathArray(pathArray);

      if (this.equalCommands(pathArray)) {
        this.destination = pathArray;
      } else {
        this.destination = null;
      }

      return this;
    },
    // Get morphed path array at given position
    at: function at(pos) {
      // make sure a destination is defined
      if (!this.destination) return this;
      var sourceArray = this;
      var destinationArray = this.destination.value;
      var array = [];
      var pathArray = new PathArray();
      var i, il, j, jl; // Animate has specified in the SVG spec
      // See: https://www.w3.org/TR/SVG11/paths.html#PathElement

      for (i = 0, il = sourceArray.length; i < il; i++) {
        array[i] = [sourceArray[i][0]];

        for (j = 1, jl = sourceArray[i].length; j < jl; j++) {
          array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos;
        } // For the two flags of the elliptical arc command, the SVG spec say:
        // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
        // Elliptical arc command as an array followed by corresponding indexes:
        // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
        //   0    1   2        3                 4             5      6  7


        if (array[i][0] === 'A') {
          array[i][4] = +(array[i][4] !== 0);
          array[i][5] = +(array[i][5] !== 0);
        }
      } // Directly modify the value of a path array, this is done this way for performance


      pathArray.value = array;
      return pathArray;
    },
    // Absolutize and parse path to array
    parse: function parse() {
      var array = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [['M', 0, 0]]; // if it's already a patharray, no need to parse it

      if (array instanceof PathArray) return array; // prepare for parsing

      var s;
      var paramCnt = {
        M: 2,
        L: 2,
        H: 1,
        V: 1,
        C: 6,
        S: 4,
        Q: 4,
        T: 2,
        A: 7,
        Z: 0
      };

      if (typeof array === 'string') {
        array = array.replace(numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
        .replace(pathLetters, ' $& ') // put some room between letters and numbers
        .replace(hyphen, '$1 -') // add space before hyphen
        .trim() // trim
        .split(delimiter); // split into array
      } else {
        array = array.reduce(function (prev, curr) {
          return [].concat.call(prev, curr);
        }, []);
      } // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]


      var result = [];
      var p = new Point();
      var p0 = new Point();
      var index = 0;
      var len = array.length;

      do {
        // Test if we have a path letter
        if (isPathLetter.test(array[index])) {
          s = array[index];
          ++index; // If last letter was a move command and we got no new, it defaults to [L]ine
        } else if (s === 'M') {
          s = 'L';
        } else if (s === 'm') {
          s = 'l';
        }

        result.push(pathHandlers[s].call(null, array.slice(index, index = index + paramCnt[s.toUpperCase()]).map(parseFloat), p, p0));
      } while (len > index);

      return result;
    },
    // Get bounding box of path
    bbox: function bbox() {
      parser().path.setAttribute('d', this.toString());
      return parser.nodes.path.getBBox();
    }
  });

  var Morphable = /*#__PURE__*/function () {
    function Morphable(stepper) {
      _classCallCheck(this, Morphable);

      this._stepper = stepper || new Ease('-');
      this._from = null;
      this._to = null;
      this._type = null;
      this._context = null;
      this._morphObj = null;
    }

    _createClass(Morphable, [{
      key: "from",
      value: function from(val) {
        if (val == null) {
          return this._from;
        }

        this._from = this._set(val);
        return this;
      }
    }, {
      key: "to",
      value: function to(val) {
        if (val == null) {
          return this._to;
        }

        this._to = this._set(val);
        return this;
      }
    }, {
      key: "type",
      value: function type(_type) {
        // getter
        if (_type == null) {
          return this._type;
        } // setter


        this._type = _type;
        return this;
      }
    }, {
      key: "_set",
      value: function _set(value) {
        if (!this._type) {
          var type = _typeof(value);

          if (type === 'number') {
            this.type(SVGNumber);
          } else if (type === 'string') {
            if (Color.isColor(value)) {
              this.type(Color);
            } else if (delimiter.test(value)) {
              this.type(pathLetters.test(value) ? PathArray : SVGArray);
            } else if (numberAndUnit.test(value)) {
              this.type(SVGNumber);
            } else {
              this.type(NonMorphable);
            }
          } else if (morphableTypes.indexOf(value.constructor) > -1) {
            this.type(value.constructor);
          } else if (Array.isArray(value)) {
            this.type(SVGArray);
          } else if (type === 'object') {
            this.type(ObjectBag);
          } else {
            this.type(NonMorphable);
          }
        }

        var result = new this._type(value);

        if (this._type === Color) {
          result = this._to ? result[this._to[4]]() : this._from ? result[this._from[4]]() : result;
        }

        result = result.toArray();
        this._morphObj = this._morphObj || new this._type();
        this._context = this._context || Array.apply(null, Array(result.length)).map(Object).map(function (o) {
          o.done = true;
          return o;
        });
        return result;
      }
    }, {
      key: "stepper",
      value: function stepper(_stepper) {
        if (_stepper == null) return this._stepper;
        this._stepper = _stepper;
        return this;
      }
    }, {
      key: "done",
      value: function done() {
        var complete = this._context.map(this._stepper.done).reduce(function (last, curr) {
          return last && curr;
        }, true);

        return complete;
      }
    }, {
      key: "at",
      value: function at(pos) {
        var _this = this;

        return this._morphObj.fromArray(this._from.map(function (i, index) {
          return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context);
        }));
      }
    }]);

    return Morphable;
  }();

  var NonMorphable = /*#__PURE__*/function () {
    function NonMorphable() {
      _classCallCheck(this, NonMorphable);

      this.init.apply(this, arguments);
    }

    _createClass(NonMorphable, [{
      key: "init",
      value: function init(val) {
        val = Array.isArray(val) ? val[0] : val;
        this.value = val;
        return this;
      }
    }, {
      key: "valueOf",
      value: function valueOf() {
        return this.value;
      }
    }, {
      key: "toArray",
      value: function toArray() {
        return [this.value];
      }
    }]);

    return NonMorphable;
  }();

  var TransformBag = /*#__PURE__*/function () {
    function TransformBag() {
      _classCallCheck(this, TransformBag);

      this.init.apply(this, arguments);
    }

    _createClass(TransformBag, [{
      key: "init",
      value: function init(obj) {
        if (Array.isArray(obj)) {
          obj = {
            scaleX: obj[0],
            scaleY: obj[1],
            shear: obj[2],
            rotate: obj[3],
            translateX: obj[4],
            translateY: obj[5],
            originX: obj[6],
            originY: obj[7]
          };
        }

        Object.assign(this, TransformBag.defaults, obj);
        return this;
      }
    }, {
      key: "toArray",
      value: function toArray() {
        var v = this;
        return [v.scaleX, v.scaleY, v.shear, v.rotate, v.translateX, v.translateY, v.originX, v.originY];
      }
    }]);

    return TransformBag;
  }();

  TransformBag.defaults = {
    scaleX: 1,
    scaleY: 1,
    shear: 0,
    rotate: 0,
    translateX: 0,
    translateY: 0,
    originX: 0,
    originY: 0
  };

  var ObjectBag = /*#__PURE__*/function () {
    function ObjectBag() {
      _classCallCheck(this, ObjectBag);

      this.init.apply(this, arguments);
    }

    _createClass(ObjectBag, [{
      key: "init",
      value: function init(objOrArr) {
        this.values = [];

        if (Array.isArray(objOrArr)) {
          this.values = objOrArr;
          return;
        }

        objOrArr = objOrArr || {};
        var entries = [];

        for (var i in objOrArr) {
          entries.push([i, objOrArr[i]]);
        }

        entries.sort(function (a, b) {
          return a[0] - b[0];
        });
        this.values = entries.reduce(function (last, curr) {
          return last.concat(curr);
        }, []);
        return this;
      }
    }, {
      key: "valueOf",
      value: function valueOf() {
        var obj = {};
        var arr = this.values;

        for (var i = 0, len = arr.length; i < len; i += 2) {
          obj[arr[i]] = arr[i + 1];
        }

        return obj;
      }
    }, {
      key: "toArray",
      value: function toArray() {
        return this.values;
      }
    }]);

    return ObjectBag;
  }();

  var morphableTypes = [NonMorphable, TransformBag, ObjectBag];

  function registerMorphableType() {
    var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
    morphableTypes.push.apply(morphableTypes, _toConsumableArray([].concat(type)));
  }

  function makeMorphable() {
    extend(morphableTypes, {
      to: function to(val) {
        return new Morphable().type(this.constructor).from(this.valueOf()).to(val);
      },
      fromArray: function fromArray(arr) {
        this.init(arr);
        return this;
      }
    });
  }

  var Path = /*#__PURE__*/function (_Shape) {
    _inherits(Path, _Shape); // Initialize node


    function Path(node) {
      _classCallCheck(this, Path);

      return _possibleConstructorReturn(this, _getPrototypeOf(Path).call(this, nodeOrNew('path', node), node));
    } // Get array


    _createClass(Path, [{
      key: "array",
      value: function array() {
        return this._array || (this._array = new PathArray(this.attr('d')));
      } // Plot new path

    }, {
      key: "plot",
      value: function plot(d) {
        return d == null ? this.array() : this.clear().attr('d', typeof d === 'string' ? d : this._array = new PathArray(d));
      } // Clear array cache

    }, {
      key: "clear",
      value: function clear() {
        delete this._array;
        return this;
      } // Move by left top corner

    }, {
      key: "move",
      value: function move(x, y) {
        return this.attr('d', this.array().move(x, y));
      } // Move by left top corner over x-axis

    }, {
      key: "x",
      value: function x(_x) {
        return _x == null ? this.bbox().x : this.move(_x, this.bbox().y);
      } // Move by left top corner over y-axis

    }, {
      key: "y",
      value: function y(_y) {
        return _y == null ? this.bbox().y : this.move(this.bbox().x, _y);
      } // Set element size to given width and height

    }, {
      key: "size",
      value: function size(width, height) {
        var p = proportionalSize(this, width, height);
        return this.attr('d', this.array().size(p.width, p.height));
      } // Set width of element

    }, {
      key: "width",
      value: function width(_width) {
        return _width == null ? this.bbox().width : this.size(_width, this.bbox().height);
      } // Set height of element

    }, {
      key: "height",
      value: function height(_height) {
        return _height == null ? this.bbox().height : this.size(this.bbox().width, _height);
      }
    }, {
      key: "targets",
      value: function targets() {
        return baseFind('svg textpath [href*="' + this.id() + '"]');
      }
    }]);

    return Path;
  }(Shape); // Define morphable array


  Path.prototype.MorphArray = PathArray; // Add parent method

  registerMethods({
    Container: {
      // Create a wrapped path element
      path: wrapWithAttrCheck(function (d) {
        // make sure plot is called as a setter
        return this.put(new Path()).plot(d || new PathArray());
      })
    }
  });
  register(Path, 'Path');

  function array() {
    return this._array || (this._array = new PointArray(this.attr('points')));
  } // Plot new path


  function plot(p) {
    return p == null ? this.array() : this.clear().attr('points', typeof p === 'string' ? p : this._array = new PointArray(p));
  } // Clear array cache


  function clear() {
    delete this._array;
    return this;
  } // Move by left top corner


  function move(x, y) {
    return this.attr('points', this.array().move(x, y));
  } // Set element size to given width and height


  function size(width, height) {
    var p = proportionalSize(this, width, height);
    return this.attr('points', this.array().size(p.width, p.height));
  }

  var poly = {
    __proto__: null,
    array: array,
    plot: plot,
    clear: clear,
    move: move,
    size: size
  };

  var Polygon = /*#__PURE__*/function (_Shape) {
    _inherits(Polygon, _Shape); // Initialize node


    function Polygon(node) {
      _classCallCheck(this, Polygon);

      return _possibleConstructorReturn(this, _getPrototypeOf(Polygon).call(this, nodeOrNew('polygon', node), node));
    }

    return Polygon;
  }(Shape);

  registerMethods({
    Container: {
      // Create a wrapped polygon element
      polygon: wrapWithAttrCheck(function (p) {
        // make sure plot is called as a setter
        return this.put(new Polygon()).plot(p || new PointArray());
      })
    }
  });
  extend(Polygon, pointed);
  extend(Polygon, poly);
  register(Polygon, 'Polygon');

  var Polyline = /*#__PURE__*/function (_Shape) {
    _inherits(Polyline, _Shape); // Initialize node


    function Polyline(node) {
      _classCallCheck(this, Polyline);

      return _possibleConstructorReturn(this, _getPrototypeOf(Polyline).call(this, nodeOrNew('polyline', node), node));
    }

    return Polyline;
  }(Shape);

  registerMethods({
    Container: {
      // Create a wrapped polygon element
      polyline: wrapWithAttrCheck(function (p) {
        // make sure plot is called as a setter
        return this.put(new Polyline()).plot(p || new PointArray());
      })
    }
  });
  extend(Polyline, pointed);
  extend(Polyline, poly);
  register(Polyline, 'Polyline');

  var Rect = /*#__PURE__*/function (_Shape) {
    _inherits(Rect, _Shape); // Initialize node


    function Rect(node) {
      _classCallCheck(this, Rect);

      return _possibleConstructorReturn(this, _getPrototypeOf(Rect).call(this, nodeOrNew('rect', node), node));
    }

    return Rect;
  }(Shape);

  extend(Rect, {
    rx: rx,
    ry: ry
  });
  registerMethods({
    Container: {
      // Create a rect element
      rect: wrapWithAttrCheck(function (width, height) {
        return this.put(new Rect()).size(width, height);
      })
    }
  });
  register(Rect, 'Rect');
  var max$3 = Math.max;
  var min$4 = Math.min;
  var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
  var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded'; // `Array.prototype.splice` method
  // https://tc39.github.io/ecma262/#sec-array.prototype.splice
  // with adding support of @@species

  _export({
    target: 'Array',
    proto: true,
    forced: !arrayMethodHasSpeciesSupport('splice')
  }, {
    splice: function splice(start, deleteCount
    /* , ...items */
    ) {
      var O = toObject(this);
      var len = toLength(O.length);
      var actualStart = toAbsoluteIndex(start, len);
      var argumentsLength = arguments.length;
      var insertCount, actualDeleteCount, A, k, from, to;

      if (argumentsLength === 0) {
        insertCount = actualDeleteCount = 0;
      } else if (argumentsLength === 1) {
        insertCount = 0;
        actualDeleteCount = len - actualStart;
      } else {
        insertCount = argumentsLength - 2;
        actualDeleteCount = min$4(max$3(toInteger(deleteCount), 0), len - actualStart);
      }

      if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) {
        throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
      }

      A = arraySpeciesCreate(O, actualDeleteCount);

      for (k = 0; k < actualDeleteCount; k++) {
        from = actualStart + k;
        if (from in O) createProperty(A, k, O[from]);
      }

      A.length = actualDeleteCount;

      if (insertCount < actualDeleteCount) {
        for (k = actualStart; k < len - actualDeleteCount; k++) {
          from = k + actualDeleteCount;
          to = k + insertCount;
          if (from in O) O[to] = O[from];else delete O[to];
        }

        for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
      } else if (insertCount > actualDeleteCount) {
        for (k = len - actualDeleteCount; k > actualStart; k--) {
          from = k + actualDeleteCount - 1;
          to = k + insertCount - 1;
          if (from in O) O[to] = O[from];else delete O[to];
        }
      }

      for (k = 0; k < insertCount; k++) {
        O[k + actualStart] = arguments[k + 2];
      }

      O.length = len - actualDeleteCount + insertCount;
      return A;
    }
  });

  var Queue = /*#__PURE__*/function () {
    function Queue() {
      _classCallCheck(this, Queue);

      this._first = null;
      this._last = null;
    }

    _createClass(Queue, [{
      key: "push",
      value: function push(value) {
        // An item stores an id and the provided value
        var item = value.next ? value : {
          value: value,
          next: null,
          prev: null
        }; // Deal with the queue being empty or populated

        if (this._last) {
          item.prev = this._last;
          this._last.next = item;
          this._last = item;
        } else {
          this._last = item;
          this._first = item;
        } // Return the current item


        return item;
      }
    }, {
      key: "shift",
      value: function shift() {
        // Check if we have a value
        var remove = this._first;
        if (!remove) return null; // If we do, remove it and relink things

        this._first = remove.next;
        if (this._first) this._first.prev = null;
        this._last = this._first ? this._last : null;
        return remove.value;
      } // Shows us the first item in the list

    }, {
      key: "first",
      value: function first() {
        return this._first && this._first.value;
      } // Shows us the last item in the list

    }, {
      key: "last",
      value: function last() {
        return this._last && this._last.value;
      } // Removes the item that was returned from the push

    }, {
      key: "remove",
      value: function remove(item) {
        // Relink the previous item
        if (item.prev) item.prev.next = item.next;
        if (item.next) item.next.prev = item.prev;
        if (item === this._last) this._last = item.prev;
        if (item === this._first) this._first = item.next; // Invalidate item

        item.prev = null;
        item.next = null;
      }
    }]);

    return Queue;
  }();

  var Animator = {
    nextDraw: null,
    frames: new Queue(),
    timeouts: new Queue(),
    immediates: new Queue(),
    timer: function timer() {
      return globals.window.performance || globals.window.Date;
    },
    transforms: [],
    frame: function frame(fn) {
      // Store the node
      var node = Animator.frames.push({
        run: fn
      }); // Request an animation frame if we don't have one

      if (Animator.nextDraw === null) {
        Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw);
      } // Return the node so we can remove it easily


      return node;
    },
    timeout: function timeout(fn, delay) {
      delay = delay || 0; // Work out when the event should fire

      var time = Animator.timer().now() + delay; // Add the timeout to the end of the queue

      var node = Animator.timeouts.push({
        run: fn,
        time: time
      }); // Request another animation frame if we need one

      if (Animator.nextDraw === null) {
        Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw);
      }

      return node;
    },
    immediate: function immediate(fn) {
      // Add the immediate fn to the end of the queue
      var node = Animator.immediates.push(fn); // Request another animation frame if we need one

      if (Animator.nextDraw === null) {
        Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw);
      }

      return node;
    },
    cancelFrame: function cancelFrame(node) {
      node != null && Animator.frames.remove(node);
    },
    clearTimeout: function clearTimeout(node) {
      node != null && Animator.timeouts.remove(node);
    },
    cancelImmediate: function cancelImmediate(node) {
      node != null && Animator.immediates.remove(node);
    },
    _draw: function _draw(now) {
      // Run all the timeouts we can run, if they are not ready yet, add them
      // to the end of the queue immediately! (bad timeouts!!! [sarcasm])
      var nextTimeout = null;
      var lastTimeout = Animator.timeouts.last();

      while (nextTimeout = Animator.timeouts.shift()) {
        // Run the timeout if its time, or push it to the end
        if (now >= nextTimeout.time) {
          nextTimeout.run();
        } else {
          Animator.timeouts.push(nextTimeout);
        } // If we hit the last item, we should stop shifting out more items


        if (nextTimeout === lastTimeout) break;
      } // Run all of the animation frames


      var nextFrame = null;
      var lastFrame = Animator.frames.last();

      while (nextFrame !== lastFrame && (nextFrame = Animator.frames.shift())) {
        nextFrame.run(now);
      }

      var nextImmediate = null;

      while (nextImmediate = Animator.immediates.shift()) {
        nextImmediate();
      } // If we have remaining timeouts or frames, draw until we don't anymore


      Animator.nextDraw = Animator.timeouts.first() || Animator.frames.first() ? globals.window.requestAnimationFrame(Animator._draw) : null;
    }
  };

  var makeSchedule = function makeSchedule(runnerInfo) {
    var start = runnerInfo.start;
    var duration = runnerInfo.runner.duration();
    var end = start + duration;
    return {
      start: start,
      duration: duration,
      end: end,
      runner: runnerInfo.runner
    };
  };

  var defaultSource = function defaultSource() {
    var w = globals.window;
    return (w.performance || w.Date).now();
  };

  var Timeline = /*#__PURE__*/function (_EventTarget) {
    _inherits(Timeline, _EventTarget); // Construct a new timeline on the given element


    function Timeline() {
      var _this;

      var timeSource = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultSource;

      _classCallCheck(this, Timeline);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(Timeline).call(this));
      _this._timeSource = timeSource; // Store the timing variables

      _this._startTime = 0;
      _this._speed = 1.0; // Determines how long a runner is hold in memory. Can be a dt or true/false

      _this._persist = 0; // Keep track of the running animations and their starting parameters

      _this._nextFrame = null;
      _this._paused = true;
      _this._runners = [];
      _this._runnerIds = [];
      _this._lastRunnerId = -1;
      _this._time = 0;
      _this._lastSourceTime = 0;
      _this._lastStepTime = 0; // Make sure that step is always called in class context

      _this._step = _this._stepFn.bind(_assertThisInitialized(_this), false);
      _this._stepImmediate = _this._stepFn.bind(_assertThisInitialized(_this), true);
      return _this;
    } // schedules a runner on the timeline


    _createClass(Timeline, [{
      key: "schedule",
      value: function schedule(runner, delay, when) {
        if (runner == null) {
          return this._runners.map(makeSchedule);
        } // The start time for the next animation can either be given explicitly,
        // derived from the current timeline time or it can be relative to the
        // last start time to chain animations direclty


        var absoluteStartTime = 0;
        var endTime = this.getEndTime();
        delay = delay || 0; // Work out when to start the animation

        if (when == null || when === 'last' || when === 'after') {
          // Take the last time and increment
          absoluteStartTime = endTime;
        } else if (when === 'absolute' || when === 'start') {
          absoluteStartTime = delay;
          delay = 0;
        } else if (when === 'now') {
          absoluteStartTime = this._time;
        } else if (when === 'relative') {
          var _runnerInfo = this._runners[runner.id];

          if (_runnerInfo) {
            absoluteStartTime = _runnerInfo.start + delay;
            delay = 0;
          }
        } else {
          throw new Error('Invalid value for the "when" parameter');
        } // Manage runner


        runner.unschedule();
        runner.timeline(this);
        var persist = runner.persist();
        var runnerInfo = {
          persist: persist === null ? this._persist : persist,
          start: absoluteStartTime + delay,
          runner: runner
        };
        this._lastRunnerId = runner.id;

        this._runners.push(runnerInfo);

        this._runners.sort(function (a, b) {
          return a.start - b.start;
        });

        this._runnerIds = this._runners.map(function (info) {
          return info.runner.id;
        });

        this.updateTime()._continue();

        return this;
      } // Remove the runner from this timeline

    }, {
      key: "unschedule",
      value: function unschedule(runner) {
        var index = this._runnerIds.indexOf(runner.id);

        if (index < 0) return this;

        this._runners.splice(index, 1);

        this._runnerIds.splice(index, 1);

        runner.timeline(null);
        return this;
      } // Calculates the end of the timeline

    }, {
      key: "getEndTime",
      value: function getEndTime() {
        var lastRunnerInfo = this._runners[this._runnerIds.indexOf(this._lastRunnerId)];

        var lastDuration = lastRunnerInfo ? lastRunnerInfo.runner.duration() : 0;
        var lastStartTime = lastRunnerInfo ? lastRunnerInfo.start : 0;
        return lastStartTime + lastDuration;
      }
    }, {
      key: "getEndTimeOfTimeline",
      value: function getEndTimeOfTimeline() {
        var lastEndTime = 0;

        for (var i = 0; i < this._runners.length; i++) {
          var runnerInfo = this._runners[i];
          var duration = runnerInfo ? runnerInfo.runner.duration() : 0;
          var startTime = runnerInfo ? runnerInfo.start : 0;
          var endTime = startTime + duration;

          if (endTime > lastEndTime) {
            lastEndTime = endTime;
          }
        }

        return lastEndTime;
      } // Makes sure, that after pausing the time doesn't jump

    }, {
      key: "updateTime",
      value: function updateTime() {
        if (!this.active()) {
          this._lastSourceTime = this._timeSource();
        }

        return this;
      }
    }, {
      key: "play",
      value: function play() {
        // Now make sure we are not paused and continue the animation
        this._paused = false;
        return this.updateTime()._continue();
      }
    }, {
      key: "pause",
      value: function pause() {
        this._paused = true;
        return this._continue();
      }
    }, {
      key: "stop",
      value: function stop() {
        // Go to start and pause
        this.time(0);
        return this.pause();
      }
    }, {
      key: "finish",
      value: function finish() {
        // Go to end and pause
        this.time(this.getEndTimeOfTimeline() + 1);
        return this.pause();
      }
    }, {
      key: "speed",
      value: function speed(_speed) {
        if (_speed == null) return this._speed;
        this._speed = _speed;
        return this;
      }
    }, {
      key: "reverse",
      value: function reverse(yes) {
        var currentSpeed = this.speed();
        if (yes == null) return this.speed(-currentSpeed);
        var positive = Math.abs(currentSpeed);
        return this.speed(yes ? positive : -positive);
      }
    }, {
      key: "seek",
      value: function seek(dt) {
        return this.time(this._time + dt);
      }
    }, {
      key: "time",
      value: function time(_time) {
        if (_time == null) return this._time;
        this._time = _time;
        return this._continue(true);
      }
    }, {
      key: "persist",
      value: function persist(dtOrForever) {
        if (dtOrForever == null) return this._persist;
        this._persist = dtOrForever;
        return this;
      }
    }, {
      key: "source",
      value: function source(fn) {
        if (fn == null) return this._timeSource;
        this._timeSource = fn;
        return this;
      }
    }, {
      key: "_stepFn",
      value: function _stepFn() {
        var immediateStep = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; // Get the time delta from the last time and update the time

        var time = this._timeSource();

        var dtSource = time - this._lastSourceTime;
        if (immediateStep) dtSource = 0;
        var dtTime = this._speed * dtSource + (this._time - this._lastStepTime);
        this._lastSourceTime = time; // Only update the time if we use the timeSource.
        // Otherwise use the current time

        if (!immediateStep) {
          // Update the time
          this._time += dtTime;
          this._time = this._time < 0 ? 0 : this._time;
        }

        this._lastStepTime = this._time;
        this.fire('time', this._time); // This is for the case that the timeline was seeked so that the time
        // is now before the startTime of the runner. Thats why we need to set
        // the runner to position 0
        // FIXME:
        // However, reseting in insertion order leads to bugs. Considering the case,
        // where 2 runners change the same attriute but in different times,
        // reseting both of them will lead to the case where the later defined
        // runner always wins the reset even if the other runner started earlier
        // and therefore should win the attribute battle
        // this can be solved by reseting them backwards

        for (var k = this._runners.length; k--;) {
          // Get and run the current runner and ignore it if its inactive
          var runnerInfo = this._runners[k];
          var runner = runnerInfo.runner; // Make sure that we give the actual difference
          // between runner start time and now

          var dtToStart = this._time - runnerInfo.start; // Dont run runner if not started yet
          // and try to reset it

          if (dtToStart <= 0) {
            runner.reset();
          }
        } // Run all of the runners directly


        var runnersLeft = false;

        for (var i = 0, len = this._runners.length; i < len; i++) {
          // Get and run the current runner and ignore it if its inactive
          var _runnerInfo2 = this._runners[i];
          var _runner = _runnerInfo2.runner;
          var dt = dtTime; // Make sure that we give the actual difference
          // between runner start time and now

          var _dtToStart = this._time - _runnerInfo2.start; // Dont run runner if not started yet


          if (_dtToStart <= 0) {
            runnersLeft = true;
            continue;
          } else if (_dtToStart < dt) {
            // Adjust dt to make sure that animation is on point
            dt = _dtToStart;
          }

          if (!_runner.active()) continue; // If this runner is still going, signal that we need another animation
          // frame, otherwise, remove the completed runner

          var finished = _runner.step(dt).done;

          if (!finished) {
            runnersLeft = true; // continue
          } else if (_runnerInfo2.persist !== true) {
            // runner is finished. And runner might get removed
            var endTime = _runner.duration() - _runner.time() + this._time;

            if (endTime + _runnerInfo2.persist < this._time) {
              // Delete runner and correct index
              _runner.unschedule();

              --i;
              --len;
            }
          }
        } // Basically: we continue when there are runners right from us in time
        // when -->, and when runners are left from us when <--


        if (runnersLeft && !(this._speed < 0 && this._time === 0) || this._runnerIds.length && this._speed < 0 && this._time > 0) {
          this._continue();
        } else {
          this.pause();
          this.fire('finished');
        }

        return this;
      } // Checks if we are running and continues the animation

    }, {
      key: "_continue",
      value: function _continue() {
        var immediateStep = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
        Animator.cancelFrame(this._nextFrame);
        this._nextFrame = null;
        if (immediateStep) return this._stepImmediate();
        if (this._paused) return this;
        this._nextFrame = Animator.frame(this._step);
        return this;
      }
    }, {
      key: "active",
      value: function active() {
        return !!this._nextFrame;
      }
    }]);

    return Timeline;
  }(EventTarget);

  registerMethods({
    Element: {
      timeline: function timeline(_timeline) {
        if (_timeline == null) {
          this._timeline = this._timeline || new Timeline();
          return this._timeline;
        } else {
          this._timeline = _timeline;
          return this;
        }
      }
    }
  });

  function ownKeys$2(object, enumerableOnly) {
    var keys = Object.keys(object);

    if (Object.getOwnPropertySymbols) {
      var symbols = Object.getOwnPropertySymbols(object);
      if (enumerableOnly) symbols = symbols.filter(function (sym) {
        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
      });
      keys.push.apply(keys, symbols);
    }

    return keys;
  }

  function _objectSpread$1(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i] != null ? arguments[i] : {};

      if (i % 2) {
        ownKeys$2(source, true).forEach(function (key) {
          _defineProperty(target, key, source[key]);
        });
      } else if (Object.getOwnPropertyDescriptors) {
        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
      } else {
        ownKeys$2(source).forEach(function (key) {
          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
        });
      }
    }

    return target;
  }

  var Runner = /*#__PURE__*/function (_EventTarget) {
    _inherits(Runner, _EventTarget);

    function Runner(options) {
      var _this;

      _classCallCheck(this, Runner);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(Runner).call(this)); // Store a unique id on the runner, so that we can identify it later

      _this.id = Runner.id++; // Ensure a default value

      options = options == null ? timeline.duration : options; // Ensure that we get a controller

      options = typeof options === 'function' ? new Controller(options) : options; // Declare all of the variables

      _this._element = null;
      _this._timeline = null;
      _this.done = false;
      _this._queue = []; // Work out the stepper and the duration

      _this._duration = typeof options === 'number' && options;
      _this._isDeclarative = options instanceof Controller;
      _this._stepper = _this._isDeclarative ? options : new Ease(); // We copy the current values from the timeline because they can change

      _this._history = {}; // Store the state of the runner

      _this.enabled = true;
      _this._time = 0;
      _this._lastTime = 0; // At creation, the runner is in reseted state

      _this._reseted = true; // Save transforms applied to this runner

      _this.transforms = new Matrix();
      _this.transformId = 1; // Looping variables

      _this._haveReversed = false;
      _this._reverse = false;
      _this._loopsDone = 0;
      _this._swing = false;
      _this._wait = 0;
      _this._times = 1;
      _this._frameId = null; // Stores how long a runner is stored after beeing done

      _this._persist = _this._isDeclarative ? true : null;
      return _this;
    }
    /*
    Runner Definitions
    ==================
    These methods help us define the runtime behaviour of the Runner or they
    help us make new runners from the current runner
    */


    _createClass(Runner, [{
      key: "element",
      value: function element(_element) {
        if (_element == null) return this._element;
        this._element = _element;

        _element._prepareRunner();

        return this;
      }
    }, {
      key: "timeline",
      value: function timeline(_timeline) {
        // check explicitly for undefined so we can set the timeline to null
        if (typeof _timeline === 'undefined') return this._timeline;
        this._timeline = _timeline;
        return this;
      }
    }, {
      key: "animate",
      value: function animate(duration, delay, when) {
        var o = Runner.sanitise(duration, delay, when);
        var runner = new Runner(o.duration);
        if (this._timeline) runner.timeline(this._timeline);
        if (this._element) runner.element(this._element);
        return runner.loop(o).schedule(o.delay, o.when);
      }
    }, {
      key: "schedule",
      value: function schedule(timeline, delay, when) {
        // The user doesn't need to pass a timeline if we already have one
        if (!(timeline instanceof Timeline)) {
          when = delay;
          delay = timeline;
          timeline = this.timeline();
        } // If there is no timeline, yell at the user...


        if (!timeline) {
          throw Error('Runner cannot be scheduled without timeline');
        } // Schedule the runner on the timeline provided


        timeline.schedule(this, delay, when);
        return this;
      }
    }, {
      key: "unschedule",
      value: function unschedule() {
        var timeline = this.timeline();
        timeline && timeline.unschedule(this);
        return this;
      }
    }, {
      key: "loop",
      value: function loop(times, swing, wait) {
        // Deal with the user passing in an object
        if (_typeof(times) === 'object') {
          swing = times.swing;
          wait = times.wait;
          times = times.times;
        } // Sanitise the values and store them


        this._times = times || Infinity;
        this._swing = swing || false;
        this._wait = wait || 0; // Allow true to be passed

        if (this._times === true) {
          this._times = Infinity;
        }

        return this;
      }
    }, {
      key: "delay",
      value: function delay(_delay) {
        return this.animate(0, _delay);
      }
      /*
      Basic Functionality
      ===================
      These methods allow us to attach basic functions to the runner directly
      */

    }, {
      key: "queue",
      value: function queue(initFn, runFn, retargetFn, isTransform) {
        this._queue.push({
          initialiser: initFn || noop,
          runner: runFn || noop,
          retarget: retargetFn,
          isTransform: isTransform,
          initialised: false,
          finished: false
        });

        var timeline = this.timeline();
        timeline && this.timeline()._continue();
        return this;
      }
    }, {
      key: "during",
      value: function during(fn) {
        return this.queue(null, fn);
      }
    }, {
      key: "after",
      value: function after(fn) {
        return this.on('finished', fn);
      }
      /*
      Runner animation methods
      ========================
      Control how the animation plays
      */

    }, {
      key: "time",
      value: function time(_time) {
        if (_time == null) {
          return this._time;
        }

        var dt = _time - this._time;
        this.step(dt);
        return this;
      }
    }, {
      key: "duration",
      value: function duration() {
        return this._times * (this._wait + this._duration) - this._wait;
      }
    }, {
      key: "loops",
      value: function loops(p) {
        var loopDuration = this._duration + this._wait;

        if (p == null) {
          var loopsDone = Math.floor(this._time / loopDuration);
          var relativeTime = this._time - loopsDone * loopDuration;
          var position = relativeTime / this._duration;
          return Math.min(loopsDone + position, this._times);
        }

        var whole = Math.floor(p);
        var partial = p % 1;
        var time = loopDuration * whole + this._duration * partial;
        return this.time(time);
      }
    }, {
      key: "persist",
      value: function persist(dtOrForever) {
        if (dtOrForever == null) return this._persist;
        this._persist = dtOrForever;
        return this;
      }
    }, {
      key: "position",
      value: function position(p) {
        // Get all of the variables we need
        var x = this._time;
        var d = this._duration;
        var w = this._wait;
        var t = this._times;
        var s = this._swing;
        var r = this._reverse;
        var position;

        if (p == null) {
          /*
          This function converts a time to a position in the range [0, 1]
          The full explanation can be found in this desmos demonstration
            https://www.desmos.com/calculator/u4fbavgche
          The logic is slightly simplified here because we can use booleans
          */
          // Figure out the value without thinking about the start or end time
          var f = function f(x) {
            var swinging = s * Math.floor(x % (2 * (w + d)) / (w + d));
            var backwards = swinging && !r || !swinging && r;
            var uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards;
            var clipped = Math.max(Math.min(uncliped, 1), 0);
            return clipped;
          }; // Figure out the value by incorporating the start time


          var endTime = t * (w + d) - w;
          position = x <= 0 ? Math.round(f(1e-5)) : x < endTime ? f(x) : Math.round(f(endTime - 1e-5));
          return position;
        } // Work out the loops done and add the position to the loops done


        var loopsDone = Math.floor(this.loops());
        var swingForward = s && loopsDone % 2 === 0;
        var forwards = swingForward && !r || r && swingForward;
        position = loopsDone + (forwards ? p : 1 - p);
        return this.loops(position);
      }
    }, {
      key: "progress",
      value: function progress(p) {
        if (p == null) {
          return Math.min(1, this._time / this.duration());
        }

        return this.time(p * this.duration());
      }
    }, {
      key: "step",
      value: function step(dt) {
        // If we are inactive, this stepper just gets skipped
        if (!this.enabled) return this; // Update the time and get the new position

        dt = dt == null ? 16 : dt;
        this._time += dt;
        var position = this.position(); // Figure out if we need to run the stepper in this frame

        var running = this._lastPosition !== position && this._time >= 0;
        this._lastPosition = position; // Figure out if we just started

        var duration = this.duration();
        var justStarted = this._lastTime <= 0 && this._time > 0;
        var justFinished = this._lastTime < duration && this._time >= duration;
        this._lastTime = this._time;

        if (justStarted) {
          this.fire('start', this);
        } // Work out if the runner is finished set the done flag here so animations
        // know, that they are running in the last step (this is good for
        // transformations which can be merged)


        var declarative = this._isDeclarative;
        this.done = !declarative && !justFinished && this._time >= duration; // Runner is running. So its not in reseted state anymore

        this._reseted = false; // Call initialise and the run function

        if (running || declarative) {
          this._initialise(running); // clear the transforms on this runner so they dont get added again and again


          this.transforms = new Matrix();

          var converged = this._run(declarative ? dt : position);

          this.fire('step', this);
        } // correct the done flag here
        // declaritive animations itself know when they converged


        this.done = this.done || converged && declarative;

        if (justFinished) {
          this.fire('finished', this);
        }

        return this;
      }
    }, {
      key: "reset",
      value: function reset() {
        if (this._reseted) return this;
        this.time(0);
        this._reseted = true;
        return this;
      }
    }, {
      key: "finish",
      value: function finish() {
        return this.step(Infinity);
      }
    }, {
      key: "reverse",
      value: function reverse(_reverse) {
        this._reverse = _reverse == null ? !this._reverse : _reverse;
        return this;
      }
    }, {
      key: "ease",
      value: function ease(fn) {
        this._stepper = new Ease(fn);
        return this;
      }
    }, {
      key: "active",
      value: function active(enabled) {
        if (enabled == null) return this.enabled;
        this.enabled = enabled;
        return this;
      }
      /*
      Private Methods
      ===============
      Methods that shouldn't be used externally
      */
      // Save a morpher to the morpher list so that we can retarget it later

    }, {
      key: "_rememberMorpher",
      value: function _rememberMorpher(method, morpher) {
        this._history[method] = {
          morpher: morpher,
          caller: this._queue[this._queue.length - 1]
        }; // We have to resume the timeline in case a controller
        // is already done without beeing ever run
        // This can happen when e.g. this is done:
        //    anim = el.animate(new SVG.Spring)
        // and later
        //    anim.move(...)

        if (this._isDeclarative) {
          var timeline = this.timeline();
          timeline && timeline.play();
        }
      } // Try to set the target for a morpher if the morpher exists, otherwise
      // do nothing and return false

    }, {
      key: "_tryRetarget",
      value: function _tryRetarget(method, target, extra) {
        if (this._history[method]) {
          // if the last method wasnt even initialised, throw it away
          if (!this._history[method].caller.initialised) {
            var index = this._queue.indexOf(this._history[method].caller);

            this._queue.splice(index, 1);

            return false;
          } // for the case of transformations, we use the special retarget function
          // which has access to the outer scope


          if (this._history[method].caller.retarget) {
            this._history[method].caller.retarget(target, extra); // for everything else a simple morpher change is sufficient

          } else {
            this._history[method].morpher.to(target);
          }

          this._history[method].caller.finished = false;
          var timeline = this.timeline();
          timeline && timeline.play();
          return true;
        }

        return false;
      } // Run each initialise function in the runner if required

    }, {
      key: "_initialise",
      value: function _initialise(running) {
        // If we aren't running, we shouldn't initialise when not declarative
        if (!running && !this._isDeclarative) return; // Loop through all of the initialisers

        for (var i = 0, len = this._queue.length; i < len; ++i) {
          // Get the current initialiser
          var current = this._queue[i]; // Determine whether we need to initialise

          var needsIt = this._isDeclarative || !current.initialised && running;
          running = !current.finished; // Call the initialiser if we need to

          if (needsIt && running) {
            current.initialiser.call(this);
            current.initialised = true;
          }
        }
      } // Run each run function for the position or dt given

    }, {
      key: "_run",
      value: function _run(positionOrDt) {
        // Run all of the _queue directly
        var allfinished = true;

        for (var i = 0, len = this._queue.length; i < len; ++i) {
          // Get the current function to run
          var current = this._queue[i]; // Run the function if its not finished, we keep track of the finished
          // flag for the sake of declarative _queue

          var converged = current.runner.call(this, positionOrDt);
          current.finished = current.finished || converged === true;
          allfinished = allfinished && current.finished;
        } // We report when all of the constructors are finished


        return allfinished;
      }
    }, {
      key: "addTransform",
      value: function addTransform(transform, index) {
        this.transforms.lmultiplyO(transform);
        return this;
      }
    }, {
      key: "clearTransform",
      value: function clearTransform() {
        this.transforms = new Matrix();
        return this;
      } // TODO: Keep track of all transformations so that deletion is faster

    }, {
      key: "clearTransformsFromQueue",
      value: function clearTransformsFromQueue() {
        if (!this.done || !this._timeline || !this._timeline._runnerIds.includes(this.id)) {
          this._queue = this._queue.filter(function (item) {
            return !item.isTransform;
          });
        }
      }
    }], [{
      key: "sanitise",
      value: function sanitise(duration, delay, when) {
        // Initialise the default parameters
        var times = 1;
        var swing = false;
        var wait = 0;
        duration = duration || timeline.duration;
        delay = delay || timeline.delay;
        when = when || 'last'; // If we have an object, unpack the values

        if (_typeof(duration) === 'object' && !(duration instanceof Stepper)) {
          delay = duration.delay || delay;
          when = duration.when || when;
          swing = duration.swing || swing;
          times = duration.times || times;
          wait = duration.wait || wait;
          duration = duration.duration || timeline.duration;
        }

        return {
          duration: duration,
          delay: delay,
          swing: swing,
          times: times,
          wait: wait,
          when: when
        };
      }
    }]);

    return Runner;
  }(EventTarget);

  Runner.id = 0;

  var FakeRunner = /*#__PURE__*/function () {
    function FakeRunner() {
      var transforms = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Matrix();
      var id = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1;
      var done = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;

      _classCallCheck(this, FakeRunner);

      this.transforms = transforms;
      this.id = id;
      this.done = done;
    }

    _createClass(FakeRunner, [{
      key: "clearTransformsFromQueue",
      value: function clearTransformsFromQueue() {}
    }]);

    return FakeRunner;
  }();

  extend([Runner, FakeRunner], {
    mergeWith: function mergeWith(runner) {
      return new FakeRunner(runner.transforms.lmultiply(this.transforms), runner.id);
    }
  }); // FakeRunner.emptyRunner = new FakeRunner()

  var lmultiply = function lmultiply(last, curr) {
    return last.lmultiplyO(curr);
  };

  var getRunnerTransform = function getRunnerTransform(runner) {
    return runner.transforms;
  };

  function mergeTransforms() {
    // Find the matrix to apply to the element and apply it
    var runners = this._transformationRunners.runners;
    var netTransform = runners.map(getRunnerTransform).reduce(lmultiply, new Matrix());
    this.transform(netTransform);

    this._transformationRunners.merge();

    if (this._transformationRunners.length() === 1) {
      this._frameId = null;
    }
  }

  var RunnerArray = /*#__PURE__*/function () {
    function RunnerArray() {
      _classCallCheck(this, RunnerArray);

      this.runners = [];
      this.ids = [];
    }

    _createClass(RunnerArray, [{
      key: "add",
      value: function add(runner) {
        if (this.runners.includes(runner)) return;
        var id = runner.id + 1;
        this.runners.push(runner);
        this.ids.push(id);
        return this;
      }
    }, {
      key: "getByID",
      value: function getByID(id) {
        return this.runners[this.ids.indexOf(id + 1)];
      }
    }, {
      key: "remove",
      value: function remove(id) {
        var index = this.ids.indexOf(id + 1);
        this.ids.splice(index, 1);
        this.runners.splice(index, 1);
        return this;
      }
    }, {
      key: "merge",
      value: function merge() {
        var _this2 = this;

        var lastRunner = null;
        this.runners.forEach(function (runner, i) {
          var condition = lastRunner && runner.done && lastRunner.done // don't merge runner when persisted on timeline
          && (!runner._timeline || !runner._timeline._runnerIds.includes(runner.id)) && (!lastRunner._timeline || !lastRunner._timeline._runnerIds.includes(lastRunner.id));

          if (condition) {
            // the +1 happens in the function
            _this2.remove(runner.id);

            _this2.edit(lastRunner.id, runner.mergeWith(lastRunner));
          }

          lastRunner = runner;
        });
        return this;
      }
    }, {
      key: "edit",
      value: function edit(id, newRunner) {
        var index = this.ids.indexOf(id + 1);
        this.ids.splice(index, 1, id + 1);
        this.runners.splice(index, 1, newRunner);
        return this;
      }
    }, {
      key: "length",
      value: function length() {
        return this.ids.length;
      }
    }, {
      key: "clearBefore",
      value: function clearBefore(id) {
        var deleteCnt = this.ids.indexOf(id + 1) || 1;
        this.ids.splice(0, deleteCnt, 0);
        this.runners.splice(0, deleteCnt, new FakeRunner()).forEach(function (r) {
          return r.clearTransformsFromQueue();
        });
        return this;
      }
    }]);

    return RunnerArray;
  }();

  registerMethods({
    Element: {
      animate: function animate(duration, delay, when) {
        var o = Runner.sanitise(duration, delay, when);
        var timeline = this.timeline();
        return new Runner(o.duration).loop(o).element(this).timeline(timeline.play()).schedule(o.delay, o.when);
      },
      delay: function delay(by, when) {
        return this.animate(0, by, when);
      },
      // this function searches for all runners on the element and deletes the ones
      // which run before the current one. This is because absolute transformations
      // overwfrite anything anyway so there is no need to waste time computing
      // other runners
      _clearTransformRunnersBefore: function _clearTransformRunnersBefore(currentRunner) {
        this._transformationRunners.clearBefore(currentRunner.id);
      },
      _currentTransform: function _currentTransform(current) {
        return this._transformationRunners.runners // we need the equal sign here to make sure, that also transformations
        // on the same runner which execute before the current transformation are
        // taken into account
        .filter(function (runner) {
          return runner.id <= current.id;
        }).map(getRunnerTransform).reduce(lmultiply, new Matrix());
      },
      _addRunner: function _addRunner(runner) {
        this._transformationRunners.add(runner); // Make sure that the runner merge is executed at the very end of
        // all Animator functions. Thats why we use immediate here to execute
        // the merge right after all frames are run


        Animator.cancelImmediate(this._frameId);
        this._frameId = Animator.immediate(mergeTransforms.bind(this));
      },
      _prepareRunner: function _prepareRunner() {
        if (this._frameId == null) {
          this._transformationRunners = new RunnerArray().add(new FakeRunner(new Matrix(this)));
        }
      }
    }
  });
  extend(Runner, {
    attr: function attr(a, v) {
      return this.styleAttr('attr', a, v);
    },
    // Add animatable styles
    css: function css(s, v) {
      return this.styleAttr('css', s, v);
    },
    styleAttr: function styleAttr(type, name, val) {
      // apply attributes individually
      if (_typeof(name) === 'object') {
        for (var key in name) {
          this.styleAttr(type, key, name[key]);
        }

        return this;
      }

      var morpher = new Morphable(this._stepper).to(val);
      this.queue(function () {
        morpher = morpher.from(this.element()[type](name));
      }, function (pos) {
        this.element()[type](name, morpher.at(pos));
        return morpher.done();
      });
      return this;
    },
    zoom: function zoom(level, point) {
      if (this._tryRetarget('zoom', to, point)) return this;
      var morpher = new Morphable(this._stepper).to(new SVGNumber(level));
      this.queue(function () {
        morpher = morpher.from(this.element().zoom());
      }, function (pos) {
        this.element().zoom(morpher.at(pos), point);
        return morpher.done();
      }, function (newLevel, newPoint) {
        point = newPoint;
        morpher.to(newLevel);
      });

      this._rememberMorpher('zoom', morpher);

      return this;
    },

    /**
     ** absolute transformations
     **/
    //
    // M v -----|-----(D M v = F v)------|----->  T v
    //
    // 1. define the final state (T) and decompose it (once)
    //    t = [tx, ty, the, lam, sy, sx]
    // 2. on every frame: pull the current state of all previous transforms
    //    (M - m can change)
    //   and then write this as m = [tx0, ty0, the0, lam0, sy0, sx0]
    // 3. Find the interpolated matrix F(pos) = m + pos * (t - m)
    //   - Note F(0) = M
    //   - Note F(1) = T
    // 4. Now you get the delta matrix as a result: D = F * inv(M)
    transform: function transform(transforms, relative, affine) {
      // If we have a declarative function, we should retarget it if possible
      relative = transforms.relative || relative;

      if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) {
        return this;
      } // Parse the parameters


      var isMatrix = Matrix.isMatrixLike(transforms);
      affine = transforms.affine != null ? transforms.affine : affine != null ? affine : !isMatrix; // Create a morepher and set its type

      var morpher = new Morphable(this._stepper).type(affine ? TransformBag : Matrix);
      var origin;
      var element;
      var current;
      var currentAngle;
      var startTransform;

      function setup() {
        // make sure element and origin is defined
        element = element || this.element();
        origin = origin || getOrigin(transforms, element);
        startTransform = new Matrix(relative ? undefined : element); // add the runner to the element so it can merge transformations

        element._addRunner(this); // Deactivate all transforms that have run so far if we are absolute


        if (!relative) {
          element._clearTransformRunnersBefore(this);
        }
      }

      function run(pos) {
        // clear all other transforms before this in case something is saved
        // on this runner. We are absolute. We dont need these!
        if (!relative) this.clearTransform();

        var _transform = new Point(origin).transform(element._currentTransform(this)),
            x = _transform.x,
            y = _transform.y;

        var target = new Matrix(_objectSpread$1({}, transforms, {
          origin: [x, y]
        }));
        var start = this._isDeclarative && current ? current : startTransform;

        if (affine) {
          target = target.decompose(x, y);
          start = start.decompose(x, y); // Get the current and target angle as it was set

          var rTarget = target.rotate;
          var rCurrent = start.rotate; // Figure out the shortest path to rotate directly

          var possibilities = [rTarget - 360, rTarget, rTarget + 360];
          var distances = possibilities.map(function (a) {
            return Math.abs(a - rCurrent);
          });
          var shortest = Math.min.apply(Math, _toConsumableArray(distances));
          var index = distances.indexOf(shortest);
          target.rotate = possibilities[index];
        }

        if (relative) {
          // we have to be careful here not to overwrite the rotation
          // with the rotate method of Matrix
          if (!isMatrix) {
            target.rotate = transforms.rotate || 0;
          }

          if (this._isDeclarative && currentAngle) {
            start.rotate = currentAngle;
          }
        }

        morpher.from(start);
        morpher.to(target);
        var affineParameters = morpher.at(pos);
        currentAngle = affineParameters.rotate;
        current = new Matrix(affineParameters);
        this.addTransform(current);

        element._addRunner(this);

        return morpher.done();
      }

      function retarget(newTransforms) {
        // only get a new origin if it changed since the last call
        if ((newTransforms.origin || 'center').toString() !== (transforms.origin || 'center').toString()) {
          origin = getOrigin(transforms, element);
        } // overwrite the old transformations with the new ones


        transforms = _objectSpread$1({}, newTransforms, {
          origin: origin
        });
      }

      this.queue(setup, run, retarget, true);
      this._isDeclarative && this._rememberMorpher('transform', morpher);
      return this;
    },
    // Animatable x-axis
    x: function x(_x, relative) {
      return this._queueNumber('x', _x);
    },
    // Animatable y-axis
    y: function y(_y) {
      return this._queueNumber('y', _y);
    },
    dx: function dx() {
      var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
      return this._queueNumberDelta('x', x);
    },
    dy: function dy() {
      var y = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
      return this._queueNumberDelta('y', y);
    },
    dmove: function dmove(x, y) {
      return this.dx(x).dy(y);
    },
    _queueNumberDelta: function _queueNumberDelta(method, to) {
      to = new SVGNumber(to); // Try to change the target if we have this method already registerd

      if (this._tryRetarget(method, to)) return this; // Make a morpher and queue the animation

      var morpher = new Morphable(this._stepper).to(to);
      var from = null;
      this.queue(function () {
        from = this.element()[method]();
        morpher.from(from);
        morpher.to(from + to);
      }, function (pos) {
        this.element()[method](morpher.at(pos));
        return morpher.done();
      }, function (newTo) {
        morpher.to(from + new SVGNumber(newTo));
      }); // Register the morpher so that if it is changed again, we can retarget it

      this._rememberMorpher(method, morpher);

      return this;
    },
    _queueObject: function _queueObject(method, to) {
      // Try to change the target if we have this method already registerd
      if (this._tryRetarget(method, to)) return this; // Make a morpher and queue the animation

      var morpher = new Morphable(this._stepper).to(to);
      this.queue(function () {
        morpher.from(this.element()[method]());
      }, function (pos) {
        this.element()[method](morpher.at(pos));
        return morpher.done();
      }); // Register the morpher so that if it is changed again, we can retarget it

      this._rememberMorpher(method, morpher);

      return this;
    },
    _queueNumber: function _queueNumber(method, value) {
      return this._queueObject(method, new SVGNumber(value));
    },
    // Animatable center x-axis
    cx: function cx(x) {
      return this._queueNumber('cx', x);
    },
    // Animatable center y-axis
    cy: function cy(y) {
      return this._queueNumber('cy', y);
    },
    // Add animatable move
    move: function move(x, y) {
      return this.x(x).y(y);
    },
    // Add animatable center
    center: function center(x, y) {
      return this.cx(x).cy(y);
    },
    // Add animatable size
    size: function size(width, height) {
      // animate bbox based size for all other elements
      var box;

      if (!width || !height) {
        box = this._element.bbox();
      }

      if (!width) {
        width = box.width / box.height * height;
      }

      if (!height) {
        height = box.height / box.width * width;
      }

      return this.width(width).height(height);
    },
    // Add animatable width
    width: function width(_width) {
      return this._queueNumber('width', _width);
    },
    // Add animatable height
    height: function height(_height) {
      return this._queueNumber('height', _height);
    },
    // Add animatable plot
    plot: function plot(a, b, c, d) {
      // Lines can be plotted with 4 arguments
      if (arguments.length === 4) {
        return this.plot([a, b, c, d]);
      }

      if (this._tryRetarget('plot', a)) return this;
      var morpher = new Morphable(this._stepper).type(this._element.MorphArray).to(a);
      this.queue(function () {
        morpher.from(this._element.array());
      }, function (pos) {
        this._element.plot(morpher.at(pos));

        return morpher.done();
      });

      this._rememberMorpher('plot', morpher);

      return this;
    },
    // Add leading method
    leading: function leading(value) {
      return this._queueNumber('leading', value);
    },
    // Add animatable viewbox
    viewbox: function viewbox(x, y, width, height) {
      return this._queueObject('viewbox', new Box(x, y, width, height));
    },
    update: function update(o) {
      if (_typeof(o) !== 'object') {
        return this.update({
          offset: arguments[0],
          color: arguments[1],
          opacity: arguments[2]
        });
      }

      if (o.opacity != null) this.attr('stop-opacity', o.opacity);
      if (o.color != null) this.attr('stop-color', o.color);
      if (o.offset != null) this.attr('offset', o.offset);
      return this;
    }
  });
  extend(Runner, {
    rx: rx,
    ry: ry,
    from: from,
    to: to
  });
  register(Runner, 'Runner');

  var Svg = /*#__PURE__*/function (_Container) {
    _inherits(Svg, _Container);

    function Svg(node) {
      var _this;

      _classCallCheck(this, Svg);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(Svg).call(this, nodeOrNew('svg', node), node));

      _this.namespace();

      return _this;
    }

    _createClass(Svg, [{
      key: "isRoot",
      value: function isRoot() {
        return !this.node.parentNode || !(this.node.parentNode instanceof globals.window.SVGElement) || this.node.parentNode.nodeName === '#document';
      } // Check if this is a root svg
      // If not, call docs from this element

    }, {
      key: "root",
      value: function root() {
        if (this.isRoot()) return this;
        return _get(_getPrototypeOf(Svg.prototype), "root", this).call(this);
      } // Add namespaces

    }, {
      key: "namespace",
      value: function namespace() {
        if (!this.isRoot()) return this.root().namespace();
        return this.attr({
          xmlns: ns,
          version: '1.1'
        }).attr('xmlns:xlink', xlink, xmlns).attr('xmlns:svgjs', svgjs, xmlns);
      } // Creates and returns defs element

    }, {
      key: "defs",
      value: function defs() {
        if (!this.isRoot()) return this.root().defs();
        return adopt(this.node.querySelector('defs')) || this.put(new Defs());
      } // custom parent method

    }, {
      key: "parent",
      value: function parent(type) {
        if (this.isRoot()) {
          return this.node.parentNode.nodeName === '#document' ? null : adopt(this.node.parentNode);
        }

        return _get(_getPrototypeOf(Svg.prototype), "parent", this).call(this, type);
      }
    }, {
      key: "clear",
      value: function clear() {
        // remove children
        while (this.node.hasChildNodes()) {
          this.node.removeChild(this.node.lastChild);
        } // remove defs reference


        delete this._defs;
        return this;
      }
    }]);

    return Svg;
  }(Container);

  registerMethods({
    Container: {
      // Create nested svg document
      nested: wrapWithAttrCheck(function () {
        return this.put(new Svg());
      })
    }
  });
  register(Svg, 'Svg', true);

  var _Symbol = /*#__PURE__*/function (_Container) {
    _inherits(_Symbol, _Container); // Initialize node


    function _Symbol(node) {
      _classCallCheck(this, _Symbol);

      return _possibleConstructorReturn(this, _getPrototypeOf(_Symbol).call(this, nodeOrNew('symbol', node), node));
    }

    return _Symbol;
  }(Container);

  registerMethods({
    Container: {
      symbol: wrapWithAttrCheck(function () {
        return this.put(new _Symbol());
      })
    }
  });
  register(_Symbol, 'Symbol');

  function plain(text) {
    // clear if build mode is disabled
    if (this._build === false) {
      this.clear();
    } // create text node


    this.node.appendChild(globals.document.createTextNode(text));
    return this;
  } // Get length of text element


  function length() {
    return this.node.getComputedTextLength();
  }

  var textable = {
    __proto__: null,
    plain: plain,
    length: length
  };

  var Text = /*#__PURE__*/function (_Shape) {
    _inherits(Text, _Shape); // Initialize node


    function Text(node) {
      var _this;

      _classCallCheck(this, Text);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(Text).call(this, nodeOrNew('text', node), node));
      _this.dom.leading = new SVGNumber(1.3); // store leading value for rebuilding

      _this._rebuild = true; // enable automatic updating of dy values

      _this._build = false; // disable build mode for adding multiple lines

      return _this;
    } // Move over x-axis
    // Text is moved its bounding box
    // text-anchor does NOT matter


    _createClass(Text, [{
      key: "x",
      value: function x(_x) {
        var box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bbox();

        if (_x == null) {
          return box.x;
        }

        return this.attr('x', this.attr('x') + _x - box.x);
      } // Move over y-axis

    }, {
      key: "y",
      value: function y(_y) {
        var box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bbox();

        if (_y == null) {
          return box.y;
        }

        return this.attr('y', this.attr('y') + _y - box.y);
      }
    }, {
      key: "move",
      value: function move(x, y) {
        var box = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.bbox();
        return this.x(x, box).y(y, box);
      } // Move center over x-axis

    }, {
      key: "cx",
      value: function cx(x) {
        var box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bbox();

        if (x == null) {
          return box.cx;
        }

        return this.attr('x', this.attr('x') + x - box.cx);
      } // Move center over y-axis

    }, {
      key: "cy",
      value: function cy(y) {
        var box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bbox();

        if (y == null) {
          return box.cy;
        }

        return this.attr('y', this.attr('y') + y - box.cy);
      }
    }, {
      key: "center",
      value: function center(x, y) {
        var box = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.bbox();
        return this.cx(x, box).cy(y, box);
      } // Set the text content

    }, {
      key: "text",
      value: function text(_text) {
        // act as getter
        if (_text === undefined) {
          var children = this.node.childNodes;
          var firstLine = 0;
          _text = '';

          for (var i = 0, len = children.length; i < len; ++i) {
            // skip textPaths - they are no lines
            if (children[i].nodeName === 'textPath') {
              if (i === 0) firstLine = 1;
              continue;
            } // add newline if its not the first child and newLined is set to true


            if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) {
              _text += '\n';
            } // add content of this node


            _text += children[i].textContent;
          }

          return _text;
        } // remove existing content


        this.clear().build(true);

        if (typeof _text === 'function') {
          // call block
          _text.call(this, this);
        } else {
          // store text and make sure text is not blank
          _text = _text.split('\n'); // build new lines

          for (var j = 0, jl = _text.length; j < jl; j++) {
            this.tspan(_text[j]).newLine();
          }
        } // disable build mode and rebuild lines


        return this.build(false).rebuild();
      } // Set / get leading

    }, {
      key: "leading",
      value: function leading(value) {
        // act as getter
        if (value == null) {
          return this.dom.leading;
        } // act as setter


        this.dom.leading = new SVGNumber(value);
        return this.rebuild();
      } // Rebuild appearance type

    }, {
      key: "rebuild",
      value: function rebuild(_rebuild) {
        // store new rebuild flag if given
        if (typeof _rebuild === 'boolean') {
          this._rebuild = _rebuild;
        } // define position of all lines


        if (this._rebuild) {
          var self = this;
          var blankLineOffset = 0;
          var leading = this.dom.leading;
          this.each(function () {
            var fontSize = globals.window.getComputedStyle(this.node).getPropertyValue('font-size');
            var dy = leading * new SVGNumber(fontSize);

            if (this.dom.newLined) {
              this.attr('x', self.attr('x'));

              if (this.text() === '\n') {
                blankLineOffset += dy;
              } else {
                this.attr('dy', dy + blankLineOffset);
                blankLineOffset = 0;
              }
            }
          });
          this.fire('rebuild');
        }

        return this;
      } // Enable / disable build mode

    }, {
      key: "build",
      value: function build(_build) {
        this._build = !!_build;
        return this;
      } // overwrite method from parent to set data properly

    }, {
      key: "setData",
      value: function setData(o) {
        this.dom = o;
        this.dom.leading = new SVGNumber(o.leading || 1.3);
        return this;
      }
    }]);

    return Text;
  }(Shape);

  extend(Text, textable);
  registerMethods({
    Container: {
      // Create text element
      text: wrapWithAttrCheck(function (text) {
        return this.put(new Text()).text(text);
      }),
      // Create plain text element
      plain: wrapWithAttrCheck(function (text) {
        return this.put(new Text()).plain(text);
      })
    }
  });
  register(Text, 'Text');

  var Tspan = /*#__PURE__*/function (_Text) {
    _inherits(Tspan, _Text); // Initialize node


    function Tspan(node) {
      _classCallCheck(this, Tspan);

      return _possibleConstructorReturn(this, _getPrototypeOf(Tspan).call(this, nodeOrNew('tspan', node), node));
    } // Set text content


    _createClass(Tspan, [{
      key: "text",
      value: function text(_text) {
        if (_text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '');
        typeof _text === 'function' ? _text.call(this, this) : this.plain(_text);
        return this;
      } // Shortcut dx

    }, {
      key: "dx",
      value: function dx(_dx) {
        return this.attr('dx', _dx);
      } // Shortcut dy

    }, {
      key: "dy",
      value: function dy(_dy) {
        return this.attr('dy', _dy);
      }
    }, {
      key: "x",
      value: function x(_x) {
        return this.attr('x', _x);
      }
    }, {
      key: "y",
      value: function y(_y) {
        return this.attr('x', _y);
      }
    }, {
      key: "move",
      value: function move(x, y) {
        return this.x(x).y(y);
      } // Create new line

    }, {
      key: "newLine",
      value: function newLine() {
        // fetch text parent
        var t = this.parent(Text); // mark new line

        this.dom.newLined = true;
        var fontSize = globals.window.getComputedStyle(this.node).getPropertyValue('font-size');
        var dy = t.dom.leading * new SVGNumber(fontSize); // apply new position

        return this.dy(dy).attr('x', t.x());
      }
    }]);

    return Tspan;
  }(Text);

  extend(Tspan, textable);
  registerMethods({
    Tspan: {
      tspan: wrapWithAttrCheck(function (text) {
        var tspan = new Tspan(); // clear if build mode is disabled

        if (!this._build) {
          this.clear();
        } // add new tspan


        this.node.appendChild(tspan.node);
        return tspan.text(text);
      })
    }
  });
  register(Tspan, 'Tspan');

  var ClipPath = /*#__PURE__*/function (_Container) {
    _inherits(ClipPath, _Container);

    function ClipPath(node) {
      _classCallCheck(this, ClipPath);

      return _possibleConstructorReturn(this, _getPrototypeOf(ClipPath).call(this, nodeOrNew('clipPath', node), node));
    } // Unclip all clipped elements and remove itself


    _createClass(ClipPath, [{
      key: "remove",
      value: function remove() {
        // unclip all targets
        this.targets().forEach(function (el) {
          el.unclip();
        }); // remove clipPath from parent

        return _get(_getPrototypeOf(ClipPath.prototype), "remove", this).call(this);
      }
    }, {
      key: "targets",
      value: function targets() {
        return baseFind('svg [clip-path*="' + this.id() + '"]');
      }
    }]);

    return ClipPath;
  }(Container);

  registerMethods({
    Container: {
      // Create clipping element
      clip: wrapWithAttrCheck(function () {
        return this.defs().put(new ClipPath());
      })
    },
    Element: {
      // Distribute clipPath to svg element
      clipWith: function clipWith(element) {
        // use given clip or create a new one
        var clipper = element instanceof ClipPath ? element : this.parent().clip().add(element); // apply mask

        return this.attr('clip-path', 'url("#' + clipper.id() + '")');
      },
      // Unclip element
      unclip: function unclip() {
        return this.attr('clip-path', null);
      },
      clipper: function clipper() {
        return this.reference('clip-path');
      }
    }
  });
  register(ClipPath, 'ClipPath');

  var ForeignObject = /*#__PURE__*/function (_Element) {
    _inherits(ForeignObject, _Element);

    function ForeignObject(node) {
      _classCallCheck(this, ForeignObject);

      return _possibleConstructorReturn(this, _getPrototypeOf(ForeignObject).call(this, nodeOrNew('foreignObject', node), node));
    }

    return ForeignObject;
  }(Element);

  registerMethods({
    Container: {
      foreignObject: wrapWithAttrCheck(function (width, height) {
        return this.put(new ForeignObject()).size(width, height);
      })
    }
  });
  register(ForeignObject, 'ForeignObject');

  var G = /*#__PURE__*/function (_Container) {
    _inherits(G, _Container);

    function G(node) {
      _classCallCheck(this, G);

      return _possibleConstructorReturn(this, _getPrototypeOf(G).call(this, nodeOrNew('g', node), node));
    }

    _createClass(G, [{
      key: "x",
      value: function x(_x) {
        var box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bbox();
        if (_x == null) return box.x;
        return this.move(_x, box.y, box);
      }
    }, {
      key: "y",
      value: function y(_y) {
        var box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bbox();
        if (_y == null) return box.y;
        return this.move(box.x, _y, box);
      }
    }, {
      key: "move",
      value: function move() {
        var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
        var box = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.bbox();
        var dx = x - box.x;
        var dy = y - box.y;
        return this.dmove(dx, dy);
      }
    }, {
      key: "dx",
      value: function dx(_dx) {
        return this.dmove(_dx, 0);
      }
    }, {
      key: "dy",
      value: function dy(_dy) {
        return this.dmove(0, _dy);
      }
    }, {
      key: "dmove",
      value: function dmove(dx, dy) {
        this.children().forEach(function (child, i) {
          // Get the childs bbox
          var bbox = child.bbox(); // Get childs matrix

          var m = new Matrix(child); // Translate childs matrix by amount and
          // transform it back into parents space

          var matrix = m.translate(dx, dy).transform(m.inverse()); // Calculate new x and y from old box

          var p = new Point(bbox.x, bbox.y).transform(matrix); // Move element

          child.move(p.x, p.y);
        });
        return this;
      }
    }, {
      key: "width",
      value: function width(_width) {
        var box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bbox();
        if (_width == null) return box.width;
        return this.size(_width, box.height, box);
      }
    }, {
      key: "height",
      value: function height(_height) {
        var box = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.bbox();
        if (_height == null) return box.height;
        return this.size(box.width, _height, box);
      }
    }, {
      key: "size",
      value: function size(width, height) {
        var box = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.bbox();
        var p = proportionalSize(this, width, height, box);
        var scaleX = p.width / box.width;
        var scaleY = p.height / box.height;
        this.children().forEach(function (child, i) {
          var o = new Point(box).transform(new Matrix(child).inverse());
          child.scale(scaleX, scaleY, o.x, o.y);
        });
        return this;
      }
    }]);

    return G;
  }(Container);

  registerMethods({
    Container: {
      // Create a group element
      group: wrapWithAttrCheck(function () {
        return this.put(new G());
      })
    }
  });
  register(G, 'G');

  var A = /*#__PURE__*/function (_Container) {
    _inherits(A, _Container);

    function A(node) {
      _classCallCheck(this, A);

      return _possibleConstructorReturn(this, _getPrototypeOf(A).call(this, nodeOrNew('a', node), node));
    } // Link url


    _createClass(A, [{
      key: "to",
      value: function to(url) {
        return this.attr('href', url, xlink);
      } // Link target attribute

    }, {
      key: "target",
      value: function target(_target) {
        return this.attr('target', _target);
      }
    }]);

    return A;
  }(Container);

  registerMethods({
    Container: {
      // Create a hyperlink element
      link: wrapWithAttrCheck(function (url) {
        return this.put(new A()).to(url);
      })
    },
    Element: {
      // Create a hyperlink element
      linkTo: function linkTo(url) {
        var link = new A();

        if (typeof url === 'function') {
          url.call(link, link);
        } else {
          link.to(url);
        }

        return this.parent().put(link).put(this);
      }
    }
  });
  register(A, 'A');

  var Mask = /*#__PURE__*/function (_Container) {
    _inherits(Mask, _Container); // Initialize node


    function Mask(node) {
      _classCallCheck(this, Mask);

      return _possibleConstructorReturn(this, _getPrototypeOf(Mask).call(this, nodeOrNew('mask', node), node));
    } // Unmask all masked elements and remove itself


    _createClass(Mask, [{
      key: "remove",
      value: function remove() {
        // unmask all targets
        this.targets().forEach(function (el) {
          el.unmask();
        }); // remove mask from parent

        return _get(_getPrototypeOf(Mask.prototype), "remove", this).call(this);
      }
    }, {
      key: "targets",
      value: function targets() {
        return baseFind('svg [mask*="' + this.id() + '"]');
      }
    }]);

    return Mask;
  }(Container);

  registerMethods({
    Container: {
      mask: wrapWithAttrCheck(function () {
        return this.defs().put(new Mask());
      })
    },
    Element: {
      // Distribute mask to svg element
      maskWith: function maskWith(element) {
        // use given mask or create a new one
        var masker = element instanceof Mask ? element : this.parent().mask().add(element); // apply mask

        return this.attr('mask', 'url("#' + masker.id() + '")');
      },
      // Unmask element
      unmask: function unmask() {
        return this.attr('mask', null);
      },
      masker: function masker() {
        return this.reference('mask');
      }
    }
  });
  register(Mask, 'Mask');

  function ownKeys$3(object, enumerableOnly) {
    var keys = Object.keys(object);

    if (Object.getOwnPropertySymbols) {
      var symbols = Object.getOwnPropertySymbols(object);
      if (enumerableOnly) symbols = symbols.filter(function (sym) {
        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
      });
      keys.push.apply(keys, symbols);
    }

    return keys;
  }

  function _objectSpread$2(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i] != null ? arguments[i] : {};

      if (i % 2) {
        ownKeys$3(source, true).forEach(function (key) {
          _defineProperty(target, key, source[key]);
        });
      } else if (Object.getOwnPropertyDescriptors) {
        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
      } else {
        ownKeys$3(source).forEach(function (key) {
          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
        });
      }
    }

    return target;
  }

  function cssRule(selector, rule) {
    if (!selector) return '';
    if (!rule) return selector;
    var ret = selector + '{';

    for (var i in rule) {
      ret += unCamelCase(i) + ':' + rule[i] + ';';
    }

    ret += '}';
    return ret;
  }

  var Style = /*#__PURE__*/function (_Element) {
    _inherits(Style, _Element);

    function Style(node) {
      _classCallCheck(this, Style);

      return _possibleConstructorReturn(this, _getPrototypeOf(Style).call(this, nodeOrNew('style', node), node));
    }

    _createClass(Style, [{
      key: "addText",
      value: function addText() {
        var w = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
        this.node.textContent += w;
        return this;
      }
    }, {
      key: "font",
      value: function font(name, src) {
        var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
        return this.rule('@font-face', _objectSpread$2({
          fontFamily: name,
          src: src
        }, params));
      }
    }, {
      key: "rule",
      value: function rule(selector, obj) {
        return this.addText(cssRule(selector, obj));
      }
    }]);

    return Style;
  }(Element);

  registerMethods('Dom', {
    style: wrapWithAttrCheck(function (selector, obj) {
      return this.put(new Style()).rule(selector, obj);
    }),
    fontface: wrapWithAttrCheck(function (name, src, params) {
      return this.put(new Style()).font(name, src, params);
    })
  });
  register(Style, 'Style');

  var TextPath = /*#__PURE__*/function (_Text) {
    _inherits(TextPath, _Text); // Initialize node


    function TextPath(node) {
      _classCallCheck(this, TextPath);

      return _possibleConstructorReturn(this, _getPrototypeOf(TextPath).call(this, nodeOrNew('textPath', node), node));
    } // return the array of the path track element


    _createClass(TextPath, [{
      key: "array",
      value: function array() {
        var track = this.track();
        return track ? track.array() : null;
      } // Plot path if any

    }, {
      key: "plot",
      value: function plot(d) {
        var track = this.track();
        var pathArray = null;

        if (track) {
          pathArray = track.plot(d);
        }

        return d == null ? pathArray : this;
      } // Get the path element

    }, {
      key: "track",
      value: function track() {
        return this.reference('href');
      }
    }]);

    return TextPath;
  }(Text);

  registerMethods({
    Container: {
      textPath: wrapWithAttrCheck(function (text, path) {
        // Convert text to instance if needed
        if (!(text instanceof Text)) {
          text = this.text(text);
        }

        return text.path(path);
      })
    },
    Text: {
      // Create path for text to run on
      path: wrapWithAttrCheck(function (track) {
        var importNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var textPath = new TextPath(); // if track is a path, reuse it

        if (!(track instanceof Path)) {
          // create path element
          track = this.defs().path(track);
        } // link textPath to path and add content


        textPath.attr('href', '#' + track, xlink); // Transplant all nodes from text to textPath

        var node;

        if (importNodes) {
          while (node = this.node.firstChild) {
            textPath.node.appendChild(node);
          }
        } // add textPath element as child node and return textPath


        return this.put(textPath);
      }),
      // Get the textPath children
      textPath: function textPath() {
        return this.findOne('textPath');
      }
    },
    Path: {
      // creates a textPath from this path
      text: wrapWithAttrCheck(function (text) {
        // Convert text to instance if needed
        if (!(text instanceof Text)) {
          text = new Text().addTo(this.parent()).text(text);
        } // Create textPath from text and path and return


        return text.path(this);
      }),
      targets: function targets() {
        return baseFind('svg [href*="' + this.id() + '"]');
      }
    }
  });
  TextPath.prototype.MorphArray = PathArray;
  register(TextPath, 'TextPath');

  var Use = /*#__PURE__*/function (_Shape) {
    _inherits(Use, _Shape);

    function Use(node) {
      _classCallCheck(this, Use);

      return _possibleConstructorReturn(this, _getPrototypeOf(Use).call(this, nodeOrNew('use', node), node));
    } // Use element as a reference


    _createClass(Use, [{
      key: "element",
      value: function element(_element, file) {
        // Set lined element
        return this.attr('href', (file || '') + '#' + _element, xlink);
      }
    }]);

    return Use;
  }(Shape);

  registerMethods({
    Container: {
      // Create a use element
      use: wrapWithAttrCheck(function (element, file) {
        return this.put(new Use()).element(element, file);
      })
    }
  });
  register(Use, 'Use');
  /* Optional Modules */

  var SVG$1 = makeInstance;
  extend([Svg, _Symbol, Image, Pattern, Marker], getMethodsFor('viewbox'));
  extend([Line, Polyline, Polygon, Path], getMethodsFor('marker'));
  extend(Text, getMethodsFor('Text'));
  extend(Path, getMethodsFor('Path'));
  extend(Defs, getMethodsFor('Defs'));
  extend([Text, Tspan], getMethodsFor('Tspan'));
  extend([Rect, Ellipse, Circle, Gradient], getMethodsFor('radius'));
  extend(EventTarget, getMethodsFor('EventTarget'));
  extend(Dom, getMethodsFor('Dom'));
  extend(Element, getMethodsFor('Element'));
  extend(Shape, getMethodsFor('Shape')); // extend(Element, getConstructor('Memory'))

  extend(Container, getMethodsFor('Container'));
  extend(Runner, getMethodsFor('Runner'));
  List.extend(getMethodNames());
  registerMorphableType([SVGNumber, Color, Box, Matrix, SVGArray, PointArray, PathArray]);
  makeMorphable();

  var svg_esm = /*#__PURE__*/Object.freeze({
    __proto__: null,
    A: A,
    Animator: Animator,
    Array: SVGArray,
    Box: Box,
    Circle: Circle,
    ClipPath: ClipPath,
    Color: Color,
    Container: Container,
    Controller: Controller,
    Defs: Defs,
    Dom: Dom,
    Ease: Ease,
    Element: Element,
    Ellipse: Ellipse,
    EventTarget: EventTarget,
    ForeignObject: ForeignObject,
    G: G,
    Gradient: Gradient,
    Image: Image,
    Line: Line,
    List: List,
    Marker: Marker,
    Mask: Mask,
    Matrix: Matrix,
    Morphable: Morphable,
    NonMorphable: NonMorphable,
    Number: SVGNumber,
    ObjectBag: ObjectBag,
    PID: PID,
    Path: Path,
    PathArray: PathArray,
    Pattern: Pattern,
    Point: Point,
    PointArray: PointArray,
    Polygon: Polygon,
    Polyline: Polyline,
    Queue: Queue,
    Rect: Rect,
    Runner: Runner,
    SVG: SVG$1,
    Shape: Shape,
    Spring: Spring,
    Stop: Stop,
    Style: Style,
    Svg: Svg,
    Symbol: _Symbol,
    Text: Text,
    TextPath: TextPath,
    Timeline: Timeline,
    TransformBag: TransformBag,
    Tspan: Tspan,
    Use: Use,
    adopt: adopt,
    assignNewId: assignNewId,
    create: create,
    defaults: defaults,
    dispatch: dispatch,
    easing: easing,
    eid: eid,
    extend: extend,
    find: baseFind,
    getClass: getClass,
    invent: invent,
    makeInstance: makeInstance,
    makeMorphable: makeMorphable,
    mockAdopt: mockAdopt,
    namespaces: namespaces,
    nodeOrNew: nodeOrNew,
    off: off,
    on: on,
    parser: parser,
    regex: regex,
    register: register,
    registerMorphableType: registerMorphableType,
    registerWindow: registerWindow,
    root: root,
    utils: utils,
    wrapWithAttrCheck: wrapWithAttrCheck
  });

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

  const {
    SVG
  } = require$$0;

  function getPaper() {
    return SVG();
  }

  var getPaper_browser = getPaper;

  function appendResiduesPosition(data, options = {}) {
    const residues = data.residues;
    const {
      leftRightBorders = 20,
      spaceBetweenResidues = 20,
      width = 600
    } = options;
    let xPos = leftRightBorders;
    let xOld = xPos;
    let line = 0; // we create a temporary paper in order to get the width of the text blocs

    const paper = getPaper_browser();

    for (let i = 0; i < residues.all.length; i++) {
      let residue = residues.all[i];
      let textWidth = getTextWidth(paper, residue.label, options);
      xPos += textWidth;

      if (xPos > width - leftRightBorders) {
        xOld = leftRightBorders;
        xPos = leftRightBorders + textWidth;
        line++;
      }

      setPaper(residue, xOld, xPos, line);
      xPos += spaceBetweenResidues;
      xOld = xPos;
    }

    residues.nbLines = line;
  }

  function setPaper(residue, xFrom, xTo, line) {
    residue.paper = {
      xFrom,
      xTo,
      line,
      usedSlots: [],
      topPosition: 0,
      bottomPosition: 0
    };
  }

  function getTextWidth(paper, label, options = {}) {
    const {
      labelFontFamily = 'Verdana',
      labelSize = 12
    } = options;
    let text = paper.text(label);
    text.font({
      family: labelFontFamily,
      size: labelSize,
      weight: 'bold',
      fill: '#888'
    });
    let textWidth = text.length() || text.bbox().width;
    text.remove();
    return textWidth;
  }

  var appendResiduesPosition_1 = appendResiduesPosition;

  function appendResults(data, analysisResult, options = {}) {
    const numberResidues = data.residues.residues.length;
    const {
      merge = {}
    } = options;
    let results = JSON.parse(JSON.stringify(analysisResult));
    results = results.filter(result => !result.type.match(/^-B[0-9]$/)); // we calculate all the lines based on the results

    for (let result of results) {
      let parts = result.type.split(/:|(?=[a-z])/); // we may have ':' but not mandatory

      if (parts.length === 2) {
        result.internal = true;

        if (parts[1].match(/^[abcd][1-9]/)) {
          [parts[0], parts[1]] = [parts[1], parts[0]];
        }

        result.to = getNumber(parts[0]) - 1;
        result.from = numberResidues - getNumber(parts[1]);
      } else {
        if (parts[0].match(/^[abcd][1-9]/)) {
          result.fromBegin = true;
          result.position = getNumber(parts[0]) - 1;
        }

        if (parts[0].match(/^[wxyz][1-9]/)) {
          result.fromEnd = true;
          result.position = numberResidues - 1 - getNumber(parts[0]);
        }
      }

      if (result.fromEnd) result.color = 'red';
      if (result.fromBegin) result.color = 'blue';

      if (result.internal) {
        switch (result.type.substring(0, 1)) {
          case 'a':
            result.color = 'green';
            break;

          case 'b':
            result.color = 'orange';
            break;

          case 'c':
            result.color = 'cyan';
            break;

          default:
            result.color = 'green';
        }
      }
    }

    if (merge.charge) {
      const unique = {};

      for (let result of results) {
        if (!unique[result.type]) {
          unique[result.type] = [];
        }

        unique[result.type].push(result);
      }

      results = [];

      for (let key in unique) {
        let current = unique[key][0];
        current.similarity = unique[key].reduce((previous, item) => previous + item.similarity, 0);
        current.similarity = Math.round(current.similarity / unique[key].length);
        results.push(current);
        current.charge = '';
      }
    }

    for (let result of results) {
      if (result.similarity > 95) {
        result.textColor = 'black';
      } else if (result.similarity > 90) {
        result.textColor = '#333';
      } else if (result.similariy > 80) {
        result.textColor = '#666';
      } else {
        result.textColor = '#999';
      }
    } // sort by residue length


    results.sort((a, b) => a.length - b.length);
    data.results = results;
  }

  function getNumber(text) {
    return Number(text.replace(/^.([0-9]+).*$/, '$1'));
  }

  var appendResults_1 = appendResults;

  function appendRows(data) {
    let allResidues = data.residues.all.sort((a, b) => a.line - b.line);
    data.rows = [];

    for (let residue of allResidues) {
      let line = residue.paper.line;

      if (!data.rows[line]) {
        data.rows[line] = {
          residues: []
        };
      }

      data.rows[line].residues.push(residue);
    }

    for (let row of data.rows) {
      row.info = {};
    }
  }

  var appendRows_1 = appendRows;

  /* eslint-disable no-loop-func */
  /**
   * For each row we calculate internals, label over and label under
   * @param {*} data
   */

  function appendRowsInformation(data) {
    for (let row of data.rows) {
      let filtered = row.residues.filter(entry => entry.fromBegin !== undefined);

      if (filtered.length > 0) {
        row.info.firstResidue = filtered[0].fromBegin;
        row.info.lastResidue = filtered[filtered.length - 1].fromBegin;
      }

      row.internals = [];
    }

    for (let result of data.results) {
      if (result.internal) {
        let fromResidue = data.residues.residues[result.from];
        let from = fromResidue.fromBegin;
        let toResidue = data.residues.residues[result.to];
        let to = toResidue.fromBegin;

        for (let row of data.rows) {
          if (from <= row.info.lastResidue && to >= row.info.firstResidue) {
            result = JSON.parse(JSON.stringify(result));
            result.fromResidue = fromResidue;

            if (from < row.info.firstResidue) {
              result.firstIndex = true;
            } else {
              row.residues.forEach((residue, index) => {
                if (residue.fromBegin === from) {
                  result.firstIndex = index;
                }
              });
            }

            result.toResidue = toResidue;

            if (to > row.info.lastResidue) {
              result.lastIndex = true;
            } else {
              row.residues.forEach((residue, index) => {
                if (residue.fromBegin === to) {
                  result.lastIndex = index;
                }
              });
            }

            row.internals.push(result);
          }
        }
      } else {
        if (result.position !== undefined && data.residues.residues[result.position]) {
          let residue = data.residues.residues[result.position];

          if (result.fromEnd) {
            residue.info.nbOver++;
            residue.results.end.push(result);
          }

          if (result.fromBegin) {
            residue.info.nbUnder++;
            residue.results.begin.push(result);
          }
        }
      }
    }

    for (let row of data.rows) {
      let maxNbOver = 0;
      let maxNbUnder = 0;

      for (let residue of row.residues) {
        if (residue.info.nbOver > maxNbOver) maxNbOver = residue.info.nbOver;
        if (residue.info.nbUnder > maxNbUnder) maxNbUnder = residue.info.nbUnder;
      }

      row.info.nbOver = maxNbOver;
      row.info.nbUnder = maxNbUnder;
    }
  }

  var appendRowsInformation_1 = appendRowsInformation;

  function addCSS(paper) {
    let cssCode = `
    .highlight {
        stroke: yellow;
        stroke-width: 5px;
        fill: red;
    }
    .highlightText {
        fill: red;
    }
    `;
    let style = paper.element('style');
    style.words(cssCode);
  }

  var addCSS_1 = addCSS;

  function addScript(paper) {
    let scriptCode = ` // <![CDATA[
        function mouseOver(evt) {
           
            let targetRange=evt.target.id.replace(/^line/,'');
            let from=targetRange.replace(/-.*/,'')*1;
            let to=targetRange.replace(/.*-/,'')*1;
            let children=evt.target.parentNode.children;
            for (let child of children) {
                if (child.id === evt.target.id) {
                    child.setAttribute('class','highlight');
                }
                if (child.nodeName === 'text' && child.id.startsWith("residue")) {
                    let residueNumber=child.id.replace(/residue-/,'')*1;
                    if (residueNumber>=from && residueNumber<=to) {
                        child.setAttribute('class','highlightText');
                    }
                }
            }
        }
        function mouseOut(evt) {
            let children=evt.target.parentNode.children;
            for (let child of children) {
                if (child.id === evt.target.id) {
                    child.setAttribute('class','');
                }
                if (child.nodeName === 'text' && child.id.startsWith("residue")) {
                    child.setAttribute('class','');
                }
            }
        }
     // ]]>
    `;
    let script = paper.element('script');
    script.attr({
      type: 'application/ecmascript'
    });
    script.words(scriptCode);
  }

  var addScript_1 = addScript;

  function drawLabel(paper, result, x, y, options) {
    let label = result.type;
    let similarity = String(Math.round(result.similarity));
    let charge = result.charge > 0 ? `+${result.charge}` : result.charge;
    let text = paper.plain(label);
    text.font({
      fill: result.textColor,
      family: options.labelFontFamily,
      weight: 'bold',
      size: options.labelSize,
      anchor: 'end'
    });
    text.attr({
      x,
      y
    });
    let textWidth = 0;
    text = paper.plain(charge);
    text.font({
      fill: result.textColor,
      family: options.labelFontFamily,
      size: options.labelSize / 2
    });
    text.attr({
      x: x + textWidth,
      y: y - options.labelSize / 2
    });
    text = paper.plain(similarity);
    text.font({
      fill: result.textColor,
      family: options.labelFontFamily,
      size: options.labelSize / 2
    });
    text.attr({
      x: x + textWidth,
      y
    });
  }

  var drawLabel_1 = drawLabel;

  function drawInternals(paper, row, options) {
    let fromX = 0;
    let toX = 0;

    for (const internal of row.internals) {
      options.verticalPosition += options.spaceBetweenInternalLines;

      if (internal.firstIndex === true) {
        fromX = 0;
      } else {
        fromX = internal.fromResidue.paper.xFrom - options.spaceBetweenResidues / 2;
      }

      if (internal.lastIndex === true) {
        toX = options.width - 1;
      } else {
        toX = internal.toResidue.paper.xTo + options.spaceBetweenResidues / 2;
      }

      let y = options.verticalPosition;
      let drawLine = paper.line(fromX, y, toX, y);
      drawLine.attr({
        onmouseover: 'mouseOver(evt)',
        onmouseout: 'mouseOut(evt)',
        id: `line${internal.fromResidue.fromBegin}-${internal.toResidue.fromBegin}`
      });
      drawLine.stroke({
        color: internal.color,
        width: options.strokeWidth
      });
      let center = (fromX + toX + internal.type.length * options.labelSize * 2 / 3) / 2;
      drawLabel_1(paper, internal, center, y - 2, options);
    }

    options.verticalPosition += options.spaceBetweenInternalLines * 2;
  }

  var drawInternals_1 = drawInternals;

  function drawReplacements(paper, data, options) {
    let replacements = data.residues.replacements;
    replacements = Object.keys(replacements).map(key => {
      return {
        key,
        ...replacements[key]
      };
    });

    for (let replacement of replacements) {
      options.verticalPosition += options.spaceBetweenInternalLines;
      let text = paper.plain(`${replacement.label} = ${replacement.key}`);
      text.font({
        fill: 'darkviolet',
        family: options.labelFontFamily,
        weight: 'bold',
        size: 10
      });
      text.attr({
        x: options.leftRightBorders,
        y: options.verticalPosition
      });
    }

    options.verticalPosition += options.spaceBetweenInternalLines;
  }

  var drawReplacements_1 = drawReplacements;

  function drawTerminals(paper, row, options) {
    for (let residue of row.residues) {
      if (!residue.results) continue;

      for (let result of residue.results.begin) {
        let line = paper.line(residue.paper.xTo + options.spaceBetweenResidues / 2, residue.paper.y, residue.paper.xTo + options.spaceBetweenResidues / 2, residue.paper.y - 8);
        line.stroke({
          color: result.color,
          width: options.strokeWidth,
          linecap: 'round'
        });
        line = paper.line(residue.paper.xTo + options.spaceBetweenResidues / 2, residue.paper.y, residue.paper.xTo + options.spaceBetweenResidues / 2 - 5, residue.paper.y + 5);
        line.stroke({
          color: result.color,
          width: options.strokeWidth,
          linecap: 'round'
        });
        drawLabel_1(paper, result, residue.paper.xTo + options.spaceBetweenResidues / 2, residue.paper.y + options.labelSize + 6 + residue.paper.bottomPosition * options.labelSize, options);
        residue.paper.bottomPosition++;
      }

      for (let result of residue.results.end) {
        let line = paper.line(residue.paper.xTo + options.spaceBetweenResidues / 2 + options.strokeWidth, residue.paper.y, residue.paper.xTo + options.spaceBetweenResidues / 2 + options.strokeWidth, residue.paper.y - 8);
        line.stroke({
          color: result.color,
          width: options.strokeWidth,
          linecap: 'round'
        });
        line = paper.line(residue.paper.xTo + options.spaceBetweenResidues / 2 + options.strokeWidth, residue.paper.y - 8, residue.paper.xTo + options.spaceBetweenResidues / 2 + 5 + options.strokeWidth, residue.paper.y - 13);
        line.stroke({
          color: result.color,
          width: options.strokeWidth,
          linecap: 'round'
        });
        drawLabel_1(paper, result, residue.paper.xTo + options.spaceBetweenResidues, residue.paper.y - 17 - residue.paper.topPosition * options.labelSize, options);
        residue.paper.topPosition++;
      }
    }
  }

  var drawTerminals_1 = drawTerminals;

  function drawSequence(paper, row, options) {
    // need to plan some space for the OVER
    options.verticalPosition += row.info.nbOver * (options.labelSize + 1);

    for (const residue of row.residues) {
      residue.paper.y = options.verticalPosition;
      let text = paper.plain(residue.label);
      let textColor = residue.replaced ? 'darkviolet' : residue.kind === 'residue' ? '#555' : '#CCC';
      text.font({
        family: options.labelFontFamily,
        size: 12,
        weight: 'bold',
        fill: textColor
      });
      text.attr({
        x: residue.paper.xFrom,
        y: residue.paper.y
      });
      text.attr({
        id: `residue-${residue.fromBegin}`
      });
    }

    drawTerminals_1(paper, row, options); // need to plan some space for the UNDER

    options.verticalPosition += row.info.nbUnder * (options.labelSize + 1);
    options.verticalPosition += options.spaceBetweenInternalLines * 2;
  }

  var drawSequence_1 = drawSequence;

  /**
   *
   * @param {string} sequence
   * @param {array} analysisResult
   * @param {object} [options={}]
   * @param {number} [options.leftRightBorders=50]
   * @param {number} [options.spaceBetweenResidues=30]
   * @param {number} [options.spaceBetweenInternalLines=12]
   * @param {number} [options.strokeWidth=2]
   * @param {string} [options.labelFontFamily='Verdana']
   * @param {number} [options.labelSize=8]
   * @param {object} [options.merge={}]
   * @param {object} [options.merge.charge] Merge results if only differs by charge
   */


  function sequenceSVG(sequence, analysisResult, options = {}) {
    const {
      width = 600,
      leftRightBorders = 50,
      spaceBetweenResidues = 30,
      spaceBetweenInternalLines = 12,
      strokeWidth = 2,
      labelFontFamily = 'Verdana',
      labelSize = 8,
      parsing,
      merge
    } = options;
    const drawOptions = {
      spaceBetweenResidues,
      leftRightBorders,
      spaceBetweenInternalLines,
      strokeWidth,
      labelSize,
      labelFontFamily,
      verticalPosition: spaceBetweenInternalLines,
      width
    };
    let data = {};
    appendResidues(data, sequence, parsing);
    appendResults_1(data, analysisResult, {
      merge
    });
    appendResiduesPosition_1(data, {
      leftRightBorders,
      spaceBetweenResidues,
      labelFontFamily,
      labelSize,
      width
    });
    appendRows_1(data);
    appendInternals_1(data);
    appendRowsInformation_1(data); // We start to create the SVG and create the paper

    const paper = getPaper_browser();
    addCSS_1(paper);
    addScript_1(paper);

    for (let row of data.rows) {
      drawInternals_1(paper, row, drawOptions);
      drawSequence_1(paper, row, drawOptions);
    }

    drawReplacements_1(paper, data, drawOptions);
    paper.size(width, drawOptions.verticalPosition);
    let svg = paper.svg();
    paper.clear();
    return svg;
  }

  var sequenceSVG_1 = sequenceSVG;

  var src$2 = {
    sequenceSVG: sequenceSVG_1
  };

  var preprocessEARanges = function preprocessRanges(ranges, targetEA) {
    ranges = JSON.parse(JSON.stringify(ranges));

    if (typeof ranges === 'string') {
      // need to convert to ranges
      let parsed = parse(ranges.replace(/[\r\n\t ]/g, ''));
      let newRanges = [];
      let current = {
        mf: '',
        min: 1,
        max: 1
      }; // example ClBr2(CH2)0-2NO
      // the idea is that has long as we don't have a range we don't really care
      // there is a limitation is that the range has to be first level of parenthesis

      let parenthesisLevel = 0;
      let currentMF = ''; // start at an atom first level or a parenthesis

      for (let item of parsed) {
        switch (item.kind) {
          case Kind.ATOM:
            if (parenthesisLevel === 0 && currentMF) {
              current.mf += currentMF;
              currentMF = '';
            }

            currentMF += item.value;
            break;

          case Kind.ISOTOPE:
            if (parenthesisLevel === 0 && currentMF) {
              current.mf += currentMF;
              currentMF = '';
            }

            currentMF += `[${item.value.isotope}${item.value.atom}]`;
            break;

          case Kind.MULTIPLIER:
            if (parenthesisLevel === 0 && currentMF) {
              current.mf += currentMF + item.value;
              currentMF = '';
            } else {
              currentMF += item.value;
            }

            break;

          case Kind.MULTIPLIER_RANGE:
            if (parenthesisLevel !== 0) {
              throw new Error('Range multiplier can only be at the first level');
            }

            newRanges.push({
              mf: currentMF,
              min: item.value.from,
              max: item.value.to
            });
            currentMF = '';
            break;

          case Kind.OPENING_PARENTHESIS:
            parenthesisLevel++;
            currentMF += '(';
            break;

          case Kind.CLOSING_PARENTHESIS:
            parenthesisLevel--;
            currentMF += ')';
            break;

          default:
            throw Error(`can not preprocess ${ranges}`);
        }
      }

      if (currentMF) {
        current.mf += currentMF;
      }

      if (current.mf) {
        newRanges.push(current);
      }

      ranges = newRanges;
    }

    let possibilities = [];

    for (let i = 0; i < ranges.length; i++) {
      let range = ranges[i];
      let min = range.min === undefined ? 0 : range.min;
      let max = range.max === undefined ? 1 : range.max;
      let possibility = {
        mf: range.mf,
        minCount: min,
        // value defined by the user
        maxCount: max,
        // value defined by the user
        targetEA: targetEA[range.mf],
        mw: 0,
        // mw till this level
        aw: 0,
        // atomic weight (mass * currentCount)
        maxRatio: 0,
        // maximum ratio possible if all next elements are 0
        currentValue: 0,
        currentCount: min - 1,
        currentUnsaturation: 0,
        initialOrder: i
      };
      possibilities.push(possibility);
      let info = new MF_1(range.mf).getInfo();
      possibility.mass = info.mass;
      possibility.unsaturation = range.unsaturation === undefined ? (info.unsaturation - 1) * 2 : range.unsaturation;
      if (possibility.mf !== info.mf) possibility.isGroup = true;
    }

    possibilities = possibilities.filter(r => r.minCount !== 0 || r.maxCount !== 0);
    possibilities.sort((a, b) => {
      return b.targetEA - a.targetEA;
    });
    return possibilities;
  };

  /**
   * Returns possible combinations
   * @param {object} [targetEA]
   * @param {object} [options={}]
   * @param {string} [options.ranges='C0-100 H0-100 O0-100 N0-100'] - range of mfs to search
   * @param {number} [options.maxElementError=0.003]
   * @param {number} [options.maxTotalError=0.01]
   * @param {number} [options.minMW=0] minimal molecular weight
   * @param {number} [options.maxMW=+Infinity] maximal molecular weight
   * @param {number} [options.unsaturation={}]
   * @param {number} [options.unsaturation.min=-Infinity] Minimal unsaturation
   * @param {number} [options.unsaturation.max=+Infinity] Maximal unsaturation
   * @param {number} [options.unsaturation.onlyInteger=false] Integer unsaturation
   * @param {number} [options.unsaturation.onlyNonInteger=false] Non integer unsaturation
   * @return {Array<object>}
   */


  var src$1 = function mfFromEA(targetEA, options = {}) {
    const {
      unsaturation = {},
      maxIterations = 1e8,
      minMW = 0,
      maxMW = +Infinity,
      ranges = [{
        mf: 'C',
        min: 0,
        max: 100
      }, {
        mf: 'H',
        min: 0,
        max: 100
      }, {
        mf: 'O',
        min: 0,
        max: 100
      }, {
        mf: 'N',
        min: 0,
        max: 100
      }],
      maxElementError = 0.003,
      maxTotalError = 0.01
    } = options;
    let filterUnsaturation = unsaturation ? true : false; // we calculate not the real unsaturation but the one before dividing by 2 + 1

    let fakeMinUnsaturation = unsaturation.min === undefined ? Number.MIN_SAFE_INTEGER : (unsaturation.min - 1) * 2;
    let fakeMaxUnsaturation = unsaturation.max === undefined ? Number.MAX_SAFE_INTEGER : (unsaturation.max - 1) * 2;
    let results = {
      mfs: [],
      info: {
        numberMFEvaluated: 0,
        numberResults: 0
      }
    };
    let orderMapping = []; // used to sort the atoms

    let possibilities = preprocessEARanges(ranges, targetEA);
    orderMapping = getOrderMapping(possibilities);
    if (possibilities.length === 0) return {
      mfs: []
    };
    let currentPosition = 0;
    let currentAtom; //  if (DEBUG) console.log('possibilities', possibilities.map((a) => `${a.mf + a.originalMinCount}-${a.originalMaxCount}`));

    mfWhile: while (true) {
      while (currentPosition < possibilities.length && currentPosition >= 0) {
        let previousAtom = currentPosition === 0 ? {
          mw: 0
        } : possibilities[currentPosition - 1];
        currentAtom = possibilities[currentPosition];

        if (currentAtom.currentCount < currentAtom.maxCount) {
          currentAtom.currentCount++;
          currentAtom.aw = currentAtom.mass * currentAtom.currentCount;
          currentAtom.mw = currentAtom.aw + previousAtom.mw;
          currentAtom.maxRatio = currentAtom.aw / currentAtom.mw; // we should check if we can reach the target

          if (currentAtom.targetEA && currentAtom.aw / currentAtom.mw - currentAtom.targetEA < -maxElementError) {
            // we already don't have enough quantity of this element and it can only become worse
            continue;
          }

          if (currentPosition < possibilities.length - 1) {
            currentPosition++;
          } else {
            break;
          }
        } else {
          currentAtom.currentCount = currentAtom.minCount - 1;
          currentPosition--;
        }
      }

      if (currentPosition < 0) {
        break;
      }

      if (results.info.numberMFEvaluated++ > maxIterations) {
        throw Error(`Iteration number is over the current maximum of: ${maxIterations}`);
      }

      if (filterUnsaturation) {
        let unsaturationValue = 0;

        for (const possibility of possibilities) {
          unsaturationValue += possibility.unsaturation * possibility.currentCount;
        }

        let isOdd = Math.abs(unsaturationValue % 2);

        if (unsaturation.onlyInteger && isOdd === 1 || unsaturation.onlyNonInteger && isOdd === 0 || fakeMinUnsaturation > unsaturationValue || fakeMaxUnsaturation < unsaturationValue) {
          continue;
        }
      }

      let mw = currentAtom.mw;
      if (mw < minMW || mw > maxMW) continue;
      let totalError = 0;

      for (let i = 0; i < possibilities.length; i++) {
        const possibility = possibilities[i];
        let ratio = possibility.mass * possibility.currentCount / mw;

        if (possibility.targetEA !== undefined) {
          let error = Math.abs(possibility.targetEA - ratio);

          if (error > maxElementError) {
            continue mfWhile;
          }

          totalError += error;
        }

        possibility.currentValue = ratio;
      }

      if (isNaN(totalError) || totalError > maxTotalError) continue;
      results.mfs.push(getResult(possibilities, totalError, orderMapping));
      results.info.numberResults++;
    }

    results.mfs.sort((a, b) => Math.abs(a.totalError) - Math.abs(b.totalError));
    return results;
  };

  function getResult(possibilities, totalError, orderMapping) {
    const result = {
      mf: '',
      totalError
    }; // we check that the first time we meet the ionization group it does not end
    // in the final result

    for (let i = 0; i < possibilities.length; i++) {
      let possibility = possibilities[orderMapping[i]];

      if (possibility.currentCount !== 0) {
        if (possibility.isGroup) {
          result.mf += `(${possibility.mf})`;

          if (possibility.currentCount !== 1) {
            result.mf += possibility.currentCount;
          }
        } else {
          result.mf += possibility.mf;

          if (possibility.currentCount !== 1) {
            result.mf += possibility.currentCount;
          }
        }
      }

      result.ea = possibilities.map(current => ({
        mf: current.mf,
        value: current.currentValue,
        expected: current.targetEA,
        error: current.targetEA === undefined ? undefined : Math.abs(current.targetEA - current.currentValue)
      }));
    }

    return result;
  }

  function getOrderMapping(possibilities) {
    let mapping = possibilities.map((p, i) => ({
      atom: p.mf,
      index: i
    }));
    mapping.sort((a, b) => {
      return src$i(a.atom, b.atom);
    });
    return mapping.map(a => a.index);
  }

  var src = {
    EMDB: src$3,
    Groups: groups$2,
    Elements: elementsAndIsotopes,
    IsotopicDistribution: src$5,
    MF: MF_1,
    Peptide: src$a,
    Nucleotide: src$9,
    Spectrum: Spectrum_1,
    getPeaks: getPeaks_1,
    getBestPeaks: getBestPeaks_1,
    generateMFs: src$e,
    Report: src$2,
    atomSorter: src$i,
    mfFromEA: src$1
  };

  return src;

})));
//# sourceMappingURL=mass-tools.js.map
